package com.peas.platform.common.core.gen;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.lang.Tuple;
import cn.hutool.core.text.CharPool;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.ReUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.poi.excel.WorkbookUtil;
import cn.hutool.setting.yaml.YamlUtil;
import com.peas.platform.common.core.constant.Constants;
import lombok.Data;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.springframework.boot.autoconfigure.SpringBootApplication;

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.sql.JDBCType;
import java.util.*;

@Slf4j
public class CodeGenerator {

    private Class<?> clazz;

    @SneakyThrows
    private void generate(Class<?> clazz, Map<ConfigType, Boolean> config) {
        this.clazz = clazz;
        SpringBootApplication sba = clazz.getAnnotation(SpringBootApplication.class);
        if (sba == null) {
            throw new RuntimeException(clazz.getName() + " is not a valid SpringBootApplication.");
        }
        File dir = new File("doc");
        File[] files = dir.listFiles();
        assert files != null;
        List<String> sqlList = new ArrayList<>();
        Arrays.sort(files, Comparator.comparing(File::getName));
        for (File file : files) {
            if (!StrUtil.endWithIgnoreCase(file.getName(), "xlsx")) {
                continue;
            }
            if (checkConfig(config, ConfigType.printExcel)) {
                System.out.println("load excel:" + file.getName());
            }
            Workbook wb = WorkbookUtil.createBook(file);
            Map<String, ExcelBean> ebs = new HashMap<>();
            for (int i = 0; i < wb.getNumberOfSheets(); i++) {
                Sheet sheet = wb.getSheetAt(i);
                ExcelBean eb = new ExcelBean();
                String remove = sheet.getRow(0).getCell(5).getStringCellValue();
                if ("remove".equals(remove)) {
                    continue;
                }
                String title = sheet.getRow(0).getCell(3).getStringCellValue();
                Assert.notBlank(title, "表名不能为空");
                title = title.toLowerCase();
                if (title.startsWith("tbl_"))
                    title = title.substring(4);
                if (title.startsWith("tbl"))
                    title = title.substring(3);
                String desc = sheet.getRow(0).getCell(1).getStringCellValue();
                Assert.notBlank(desc, "表说明不能为空");
                desc = desc.toLowerCase();
                eb.setTitle(title);
                eb.setDesc(desc);
                String module = sheet.getRow(1).getCell(1).getStringCellValue();
                Assert.notBlank(module, "所属模块不能为空");
                eb.setModule(module.toLowerCase());
                String service = sheet.getRow(1).getCell(3).getStringCellValue();
                if (StrUtil.isBlank(service)) {
                    service = StrUtil.EMPTY;
                }
                eb.setService(service);
                List<ExcelBeanItem> list = new ArrayList<>();
                for (int j = 3; j < sheet.getPhysicalNumberOfRows(); j++) {
                    String msg = "excel文件【" + file.getName() + "】，sheet页【" + sheet.getSheetName() + "】中第" + (j + 1) + "行";
                    Row row = sheet.getRow(j);
                    ExcelBeanItem ebi = new ExcelBeanItem();
                    try {
                        ebi.setName(row.getCell(0).getStringCellValue().replaceAll(" ", ""));
                        ebi.setColumn(row.getCell(1).getStringCellValue().toLowerCase());
                        ebi.setType(row.getCell(2).getStringCellValue());
                        ebi.setLength(((Double) row.getCell(3).getNumericCellValue()).intValue());
                        ebi.setPrecision(((Double) row.getCell(4).getNumericCellValue()).intValue());
                        ebi.setIsnull(row.getCell(5).getStringCellValue());
                        ebi.setDefaultVal(row.getCell(6).getStringCellValue());
                        ebi.setRemark(row.getCell(7).getStringCellValue());
                        ebi.setIsAccurate("否");
                        if (row.getCell(8) != null) {
                            ebi.setIsAccurate(row.getCell(8).getStringCellValue().toLowerCase());
                        }
                        ebi.setAutoValuePrefix(null);
                        if (row.getCell(9) != null) {
                            ebi.setAutoValuePrefix(row.getCell(9).getStringCellValue().toUpperCase());
                        }
                        ebi.setValueEnum(null);
                        if (row.getCell(10) != null) {
                            ebi.setValueEnum(row.getCell(10).getStringCellValue());
                        }
                        ebi.setValueDict(null);
                        if (row.getCell(11) != null) {
                            ebi.setValueDict(row.getCell(11).getStringCellValue());
                        }
                        ebi.setValueForeign(null);
                        if (row.getCell(12) != null) {
                            ebi.setValueForeign(row.getCell(12).getStringCellValue().toLowerCase());
                        }
                    } catch (Exception e) {
                        throw new RuntimeException(msg + "：解析单元格异常", e);
                    }
                    Assert.notBlank(ebi.getColumn(), msg + "：数据库列不能为空");
                    Assert.isFalse(ebi.getColumn().contains(" "), msg + "：不能包含空格");
                    Assert.isTrue(ReUtil.isMatch("^[a-zA-Z][a-zA-Z0-9_]+$", ebi.getColumn()), msg + "：不能包含字母、数字和下划线之外的字符");
                    ebi.setJdbcType(getJdbcTypeByExcel(i + 1, j + 1, sheet.getSheetName(), ebi.getType(), ebi.getLength(), ebi.getPrecision()));
                    list.add(ebi);
                }
                eb.setList(list);
                if (ebs.containsKey(eb.getTitle())) {
                    throw new RuntimeException("excel文件【" + file.getName() + "】，表名有重复：" + eb.getTitle());
                }
                ebs.put(eb.getTitle(), eb);
            }
            sqlList.addAll(transferSqlStr(ebs.values()));
            for (ExcelBean eb : ebs.values()) {
                genPo(config, eb);
                genDto(config, eb);
                genVo(config, eb);
                genCriteria(config, eb);
                genRepository(config, eb);
                genDomain(config, eb);
                genDomainImpl(config, eb);
                genService(config, eb);
                genServiceImpl(config, eb);
                genController(config, eb);
                genVue(config, eb);
            }
            wb.close();
        }
        genSql(config, sqlList);
    }

    public void generate(Class<?> clazz, boolean printExists, boolean printExcel, boolean printCreateTable) {
        Map<ConfigType, Boolean> config = new HashMap<>();
        config.put(ConfigType.printExists, printExists);
        config.put(ConfigType.printExcel, printExcel);
        config.put(ConfigType.printCreateTable, printCreateTable);
        generate(clazz, config);
    }

    public void generate(Class<?> clazz, boolean printExists, boolean printExcel) {
        generate(clazz, printExists, printExcel, true);
    }

    public void generate(Class<?> clazz, boolean printExists) {
        generate(clazz, printExists, true);
    }

    @SuppressWarnings("unused")
    public void generate(Class<?> clazz) {
        generate(clazz, true);
    }

    private boolean checkConfig(Map<ConfigType, Boolean> config, ConfigType key) {
        return config.get(key) != null && config.get(key);
    }

    private JDBCType getJdbcTypeByExcel(int i, int j, String sheet, String type, Integer length, Integer precision) {
        switch (type.toUpperCase()) {
            case "长文本":
            case "LOB":
            case "BLOB":
            case "CLOB":
            case "TEXT":
            case "LONGTEXT":
                return JDBCType.CLOB;
            case "字符":
            case "字符串":
            case "字符型":
            case "文本":
            case "文本型":
            case "CHAR":
            case "VARCHAR":
            case "STRING":
            case "CUKY":
            case "UNIT":
            case "CLNT":
            case "STRU":
                if (length >= 3000) {
                    return JDBCType.CLOB;
                } else {
                    return JDBCType.VARCHAR;
                }
            case "数字型":
            case "数字":
            case "整数":
            case "小数":
            case "数值":
            case "BIGINT":
            case "BIGINTEGER":
            case "INT":
            case "INTEGER":
            case "NUMBER":
            case "FLOAT":
            case "DOUBLE":
            case "NUMC":
            case "DEC":
            case "DECIMAL":
            case "BIGDECIMAL":
            case "QUAN":
            case "CURR":
            case "FLTP":
                if (precision > 0) {
                    return JDBCType.DECIMAL;
                } else {
                    if (length >= 10)
                        return JDBCType.BIGINT;
                    else
                        return JDBCType.INTEGER;
                }
            case "日期型":
            case "日期":
            case "时间":
            case "TIME":
            case "DATE":
            case "TIMESTAMP":
            case "DATS":
            case "TIMS":
            case "DATETIME":
                return JDBCType.TIMESTAMP;
            default:
                throw new RuntimeException("excel中字段类型不正确【" + type + "】，在第 " + i + " 个sheet【" + sheet + "】，第 " + j + " 行");
        }
    }

    private void writeFile(File file, List<String> list) {
        try (BufferedWriter writer = new BufferedWriter(new FileWriter(file))) {
            for (String s : list) {
                writer.write(s);
                writer.newLine();
            }
            writer.flush();
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        System.out.println("【" + file.getAbsolutePath() + "】 generated.");
    }

    private List<String> transferSqlStr(Collection<ExcelBean> coll) {
        List<ExcelBean> ebs = CollUtil.sort(coll, Comparator.comparing(ExcelBean::getTitle));
        File dir = new File("doc");
        boolean bool = dir.mkdirs();
        log.trace(String.valueOf(bool));
        List<String> list = new ArrayList<>();
        for (ExcelBean eb : ebs) {
            list.add("CREATE TABLE `tbl_" + eb.getTitle() + "`  (");
            list.add("  `id` bigint(20) COMMENT '主键ID',");
            list.add("  `deleted` int NULL DEFAULT NULL COMMENT '删除标志(0未删除，1删除)',");
            list.add("  `create_by` bigint(20) NULL DEFAULT NULL COMMENT '创建人ID',");
            list.add("  `create_time` timestamp NULL DEFAULT NULL COMMENT '创建时间',");
            list.add("  `update_by` bigint(20) NULL DEFAULT NULL COMMENT '最后修改人ID',");
            list.add("  `update_time` timestamp NULL DEFAULT NULL COMMENT '最后修改时间',");
            list.add("  `version` bigint(20) NULL DEFAULT NULL COMMENT '数据版本',");
            for (ExcelBeanItem ebi : eb.getList()) {
                switch (ebi.getJdbcType()) {
                    case CLOB:
                        list.add("  `" + ebi.getColumn() + "` longtext CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '" + ebi.getName() + "',");
                        break;
                    case VARCHAR:
                        list.add("  `" + ebi.getColumn() + "` varchar(" + ebi.getLength() + ") CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '" + ebi.getName() + "',");
                        break;
                    case DECIMAL:
                        list.add("  `" + ebi.getColumn() + "` decimal(" + ebi.getLength() + "," + ebi.getPrecision() + ") NULL DEFAULT NULL COMMENT '" + ebi.getName() + "',");
                        break;
                    case BIGINT:
                        list.add("  `" + ebi.getColumn() + "` bigint(" + ebi.getLength() + ") NULL DEFAULT NULL COMMENT '" + ebi.getName() + "',");
                        break;
                    case INTEGER:
                        list.add("  `" + ebi.getColumn() + "` int(" + ebi.getLength() + ") NULL DEFAULT NULL COMMENT '" + ebi.getName() + "',");
                        break;
                    case TIMESTAMP:
                        list.add("  `" + ebi.getColumn() + "` timestamp NULL DEFAULT NULL COMMENT '" + ebi.getName() + "',");
                        break;
                }
            }
            list.add("  PRIMARY KEY (`id`) USING BTREE");
            String desc = eb.getDesc();
            if (!desc.endsWith("表")) {
                desc = desc + "表";
            }
            list.add(") ENGINE=InnoDB CHARACTER SET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci ROW_FORMAT=Dynamic COMMENT '" + desc + "';");
            list.add("");
            list.add("");
        }
        return list;
    }

    private String prop(ExcelBeanItem ebi) {
        String s = "    private ";
        switch (ebi.getJdbcType()) {
            case CLOB:
            case VARCHAR:
                s += "String";
                break;
            case DECIMAL:
                s += "BigDecimal";
                break;
            case BIGINT:
                s += "Long";
                break;
            case INTEGER:
                s += "Integer";
                break;
            case TIMESTAMP:
                s += "Date";
                break;
        }
        s += " " + StrUtil.toCamelCase(ebi.getColumn()) + ";";
        return s;
    }

    private void genSql(Map<ConfigType, Boolean> config, List<String> list) {
        if (CollUtil.isEmpty(list)) {
            return;
        }
        list.forEach(s -> {
            if (checkConfig(config, ConfigType.printCreateTable) && s.startsWith("CREATE TABLE")) {
                System.out.println(s);
            }
        });
        File dir = new File("doc");
        boolean bool = dir.mkdirs();
        log.trace(String.valueOf(bool));
        File file = new File(dir.getAbsolutePath() + "/table.sql");
        if (file.exists()) {
            if (checkConfig(config, ConfigType.printExists)) {
                System.out.println("genSql:【" + file.getAbsolutePath() + "】 already exist, skipped.");
            }
            return;
        }
        writeFile(file, list);
    }

    private void genPo(Map<ConfigType, Boolean> config, ExcelBean eb) {
        String pkg = clazz.getPackage().getName().replaceAll("\\.", "/");
        File dir = new File("src/main/java/" + pkg + "/" + eb.getServiceModule("/") + "/adapter/repository/po");
        boolean bool = dir.mkdirs();
        log.trace(String.valueOf(bool));
        String title = StrUtil.toCamelCase(eb.getTitle());
        String Title = StrUtil.upperFirst(title);
        File file = new File(dir.getAbsolutePath() + "/" + Title + "Po.java");
        if (file.exists()) {
            if (checkConfig(config, ConfigType.printExists)) {
                System.out.println("genPo:【" + file.getAbsolutePath() + "】 already exist, skipped.");
            }
            return;
        }
        List<String> list = new ArrayList<>();
        list.add("package " + clazz.getPackage().getName() + "." + eb.getServiceModule(".") + ".adapter.repository.po;");
        list.add("");
        list.add("import java.util.*;");
        list.add("import java.math.*;");
        list.add("import com.baomidou.mybatisplus.annotation.TableField;");
        list.add("import com.baomidou.mybatisplus.annotation.TableName;");
        list.add("import com.peas.platform.common.core.annotation.Comment;");
        list.add("import com.peas.platform.framework.mybatisplus.po.BasePo;");
        list.add("import lombok.Data;");
        list.add("import lombok.EqualsAndHashCode;");
        list.add("import org.apache.ibatis.type.JdbcType;");
        list.add("import javax.validation.constraints.*;");
        list.add("");
        list.add("// " + eb.getDesc());
        list.add("@Data");
        list.add("@EqualsAndHashCode(callSuper = false)");
        list.add("@TableName(value = " + CharPool.DOUBLE_QUOTES + "`tbl_" + eb.getTitle() + "`" + CharPool.DOUBLE_QUOTES + ")");
        list.add("public class " + Title + "Po extends BasePo {");
        list.add("");
        for (ExcelBeanItem ebi : eb.getList()) {
            if (StrUtil.isBlank(ebi.getColumn())) {
                continue;
            }
            list.add("    // " + ebi.getName());
            if (StrUtil.isNotBlank(ebi.getRemark())) {
                list.add("    // " + ebi.getRemark().replaceAll("\r\n", ";").replaceAll("\n", ";"));
            }
            String str = "";
            if (StrUtil.isNotBlank(ebi.getValueEnum())) {
                list.add("    // " + Constants.VALUE_PREFIX_ENUM + ebi.getValueEnum());
                str = ", enumType = " + CharPool.DOUBLE_QUOTES + ebi.getValueEnum() + CharPool.DOUBLE_QUOTES;
            }
            if (StrUtil.isNotBlank(ebi.getValueDict())) {
                list.add("    // " + Constants.VALUE_PREFIX_DICT + ebi.getValueDict());
                str = ", dictType = " + CharPool.DOUBLE_QUOTES + ebi.getValueDict() + CharPool.DOUBLE_QUOTES;
            }
            if (StrUtil.isNotBlank(ebi.getValueForeign())) {
                list.add("    // " + Constants.VALUE_PREFIX_FOREIGN + ebi.getValueForeign());
                str = ", foreignType = " + CharPool.DOUBLE_QUOTES + ebi.getValueForeign() + CharPool.DOUBLE_QUOTES;
            }
            list.add("    @Comment(value = " + CharPool.DOUBLE_QUOTES + ebi.getName() + CharPool.DOUBLE_QUOTES + str + ")");
            switch (ebi.getJdbcType()) {
                case CLOB:
                    if ("否".equals(ebi.getIsnull()))
                        list.add("    @NotBlank(message = " + CharPool.DOUBLE_QUOTES + ebi.getName() + "不能为空" + CharPool.DOUBLE_QUOTES + ")");
                    break;
                case VARCHAR:
                    if ("否".equals(ebi.getIsnull()))
                        list.add("    @NotBlank(message = " + CharPool.DOUBLE_QUOTES + ebi.getName() + "不能为空" + CharPool.DOUBLE_QUOTES + ")");
                    list.add("    @Size(max = " + ebi.getLength() + ", message = " + CharPool.DOUBLE_QUOTES + ebi.getName() + "不能超过" + ebi.getLength() + "个字符" + CharPool.DOUBLE_QUOTES + ")");
                    break;
                case INTEGER:
                    if (ebi.getLength() != null && ebi.getLength() < 9) {
                        int max = 0;
                        for (int i = 0; i < ebi.getLength(); i++) {
                            max += NumberUtil.pow(10, i).intValue() * 9;
                        }
                        list.add("    @Max(value = " + max + ", message = " + CharPool.DOUBLE_QUOTES + ebi.getName() + "取值无效" + CharPool.DOUBLE_QUOTES + ")");
                    }
                case DECIMAL:
                case BIGINT:
                case TIMESTAMP:
                    if ("否".equals(ebi.getIsnull()))
                        list.add("    @NotNull(message = " + CharPool.DOUBLE_QUOTES + ebi.getName() + "不能为空" + CharPool.DOUBLE_QUOTES + ")");
                    break;

            }
            list.add("    @TableField(value = " + CharPool.DOUBLE_QUOTES + "`" + ebi.getColumn() + "`" + CharPool.DOUBLE_QUOTES + ", jdbcType = JdbcType." + ebi.getJdbcType().name() + ")");
            String s = prop(ebi);
            list.add(s);
            list.add("");
        }
        list.add("}");
        writeFile(file, list);
    }

    private void genRepository(Map<ConfigType, Boolean> config, ExcelBean eb) {
        String pkg = clazz.getPackage().getName().replaceAll("\\.", "/");
        File dir = new File("src/main/java/" + pkg + "/" + eb.getServiceModule("/") + "/adapter/repository");
        boolean bool = dir.mkdirs();
        log.trace(String.valueOf(bool));
        String title = StrUtil.toCamelCase(eb.getTitle());
        String Title = StrUtil.upperFirst(title);
        File file = new File(dir.getAbsolutePath() + "/" + Title + "Repository.java");
        if (file.exists()) {
            if (checkConfig(config, ConfigType.printExists)) {
                System.out.println("genRepository:【" + file.getAbsolutePath() + "】 already exist, skipped.");
            }
            return;
        }
        List<String> list = new ArrayList<>();
        list.add("package " + clazz.getPackage().getName() + "." + eb.getServiceModule(".") + ".adapter.repository;");
        list.add("");
        list.add("import com.peas.platform.framework.mybatisplus.repository.BaseRepository;");
        list.add("import " + clazz.getPackage().getName() + "." + eb.getServiceModule(".") + ".adapter.repository.po." + Title + "Po;");
        list.add("import org.apache.ibatis.annotations.Mapper;");
        list.add("");
        list.add("@Mapper");
        list.add("public interface " + Title + "Repository extends BaseRepository<" + Title + "Po> {");
        list.add("");
        list.add("}");
        writeFile(file, list);
    }

    private void genDto(Map<ConfigType, Boolean> config, ExcelBean eb) {
        String pkg = clazz.getPackage().getName().replaceAll("\\.", "/");
        File dir = new File("src/main/java/" + pkg + "/" + eb.getServiceModule("/") + "/dto");
        boolean bool = dir.mkdirs();
        log.trace(String.valueOf(bool));
        String title = StrUtil.toCamelCase(eb.getTitle());
        String Title = StrUtil.upperFirst(title);
        File file = new File(dir.getAbsolutePath() + "/" + Title + "Dto.java");
        if (file.exists()) {
            if (checkConfig(config, ConfigType.printExists)) {
                System.out.println("genDto:【" + file.getAbsolutePath() + "】 already exist, skipped.");
            }
            return;
        }
        List<String> list = new ArrayList<>();
        list.add("package " + clazz.getPackage().getName() + "." + eb.getServiceModule(".") + ".dto;");
        list.add("");
        list.add("import java.util.*;");
        list.add("import java.math.*;");
        list.add("import com.peas.platform.common.core.annotation.Comment;");
        list.add("import com.peas.platform.common.core.dto.BaseDto;");
        list.add("import com.peas.platform.framework.mybatisplus.annotation.Condition;");
        list.add("import com.peas.platform.framework.mybatisplus.annotation.ConditionOperator;");
        list.add("import lombok.Data;");
        list.add("import lombok.EqualsAndHashCode;");
        list.add("");
        list.add("// " + eb.getDesc());
        list.add("@Data");
        list.add("@EqualsAndHashCode(callSuper = false)");
        list.add("public class " + Title + "Dto extends BaseDto {");
        list.add("");
        for (ExcelBeanItem ebi : eb.getList()) {
            if (StrUtil.isBlank(ebi.getColumn())) {
                continue;
            }
            list.add("    // " + ebi.getName());
            if (StrUtil.isNotBlank(ebi.getRemark())) {
                list.add("    // " + ebi.getRemark().replaceAll("\r\n", ";").replaceAll("\n", ";"));
            }
            String str = "";
            if (StrUtil.isNotBlank(ebi.getValueEnum())) {
                list.add("    // " + Constants.VALUE_PREFIX_ENUM + ebi.getValueEnum());
                str = ", enumType = " + CharPool.DOUBLE_QUOTES + ebi.getValueEnum() + CharPool.DOUBLE_QUOTES;
            }
            if (StrUtil.isNotBlank(ebi.getValueDict())) {
                list.add("    // " + Constants.VALUE_PREFIX_DICT + ebi.getValueDict());
                str = ", dictType = " + CharPool.DOUBLE_QUOTES + ebi.getValueDict() + CharPool.DOUBLE_QUOTES;
            }
            if (StrUtil.isNotBlank(ebi.getValueForeign())) {
                list.add("    // " + Constants.VALUE_PREFIX_FOREIGN + ebi.getValueForeign());
                str = ", foreignType = " + CharPool.DOUBLE_QUOTES + ebi.getValueForeign() + CharPool.DOUBLE_QUOTES;
            }
            list.add("    @Comment(value = " + CharPool.DOUBLE_QUOTES + ebi.getName() + CharPool.DOUBLE_QUOTES + str + ")");
            String s = prop(ebi);
            if (s.contains("private String") && Arrays.asList("1", "是", "true", "y", "yes").contains(ebi.getIsAccurate())) {
                list.add("    @Condition(operator = ConditionOperator.IN)");
            }
            list.add(s);
            list.add("");
        }
        list.add("    //Criteria");
        list.add("    private Date createTime" + Constants.CRITERIA_START + ";");
        list.add("    private Date createTime" + Constants.CRITERIA_END + ";");
        list.add("    private Date updateTime" + Constants.CRITERIA_START + ";");
        list.add("    private Date updateTime" + Constants.CRITERIA_END + ";");
        for (ExcelBeanItem ebi : eb.getList()) {
            if (StrUtil.isBlank(ebi.getColumn())) {
                continue;
            }
            if (ebi.getJdbcType() == JDBCType.TIMESTAMP) {
                list.add("    private Date" + " " + StrUtil.toCamelCase(ebi.getColumn()) + Constants.CRITERIA_START + ";");
                list.add("    private Date" + " " + StrUtil.toCamelCase(ebi.getColumn()) + Constants.CRITERIA_END + ";");
            }
        }
        list.add("}");
        writeFile(file, list);
    }

    private void genDomain(Map<ConfigType, Boolean> config, ExcelBean eb) {
        String pkg = clazz.getPackage().getName().replaceAll("\\.", "/");
        File dir = new File("src/main/java/" + pkg + "/" + eb.getServiceModule("/") + "/domain");
        boolean bool = dir.mkdirs();
        log.trace(String.valueOf(bool));
        String title = StrUtil.toCamelCase(eb.getTitle());
        String Title = StrUtil.upperFirst(title);
        File file = new File(dir.getAbsolutePath() + "/" + Title + "Domain.java");
        if (file.exists()) {
            if (checkConfig(config, ConfigType.printExists)) {
                System.out.println("genDomain:【" + file.getAbsolutePath() + "】 already exist, skipped.");
            }
            return;
        }
        List<String> list = new ArrayList<>();
        list.add("package " + clazz.getPackage().getName() + "." + eb.getServiceModule(".") + ".domain;");
        list.add("");
        list.add("import com.peas.platform.framework.mybatisplus.domain.BaseDomain;");
        list.add("import " + clazz.getPackage().getName() + "." + eb.getServiceModule(".") + ".adapter.repository.po." + Title + "Po;");
        list.add("import " + clazz.getPackage().getName() + "." + eb.getServiceModule(".") + ".dto." + Title + "Dto;");
        list.add("");
        list.add("public interface " + Title + "Domain extends BaseDomain<" + Title + "Dto, " + Title + "Po> {");
        list.add("");
        list.add("}");
        writeFile(file, list);
    }

    private void genDomainImpl(Map<ConfigType, Boolean> config, ExcelBean eb) {
        String pkg = clazz.getPackage().getName().replaceAll("\\.", "/");
        File dir = new File("src/main/java/" + pkg + "/" + eb.getServiceModule("/") + "/domain/impl");
        boolean bool = dir.mkdirs();
        log.trace(String.valueOf(bool));
        String title = StrUtil.toCamelCase(eb.getTitle());
        String Title = StrUtil.upperFirst(title);
        File file = new File(dir.getAbsolutePath() + "/" + Title + "DomainImpl.java");
        if (file.exists()) {
            if (checkConfig(config, ConfigType.printExists)) {
                System.out.println("genDomainImpl:【" + file.getAbsolutePath() + "】 already exist, skipped.");
            }
            return;
        }
        List<String> list = new ArrayList<>();
        Tuple autoValueField = null;
        for (ExcelBeanItem ebi : eb.getList()) {
            if (StrUtil.isNotBlank(ebi.getAutoValuePrefix())) {
                Assert.isTrue(ebi.getAutoValuePrefix().length() <= 10, "自动生成前缀不能超过10个字符");
                Assert.isNull(autoValueField, "自动生成的字段只能有一个");
                autoValueField = new Tuple(ebi.getAutoValuePrefix().toUpperCase(), ebi);
            }
        }
        list.add("package " + clazz.getPackage().getName() + "." + eb.getServiceModule(".") + ".domain.impl;");
        list.add("");
        if (autoValueField != null) {
            list.add("import cn.hutool.core.util.StrUtil;");
        }
        list.add("import com.peas.platform.framework.mybatisplus.domain.BaseDomainImpl;");
        list.add("import com.peas.platform.framework.mybatisplus.repository.BaseRepository;");
        if (autoValueField != null) {
            list.add("import com.peas.platform.module.icims.base.sys.service.SequenceService;");// TODO
        }
        list.add("import " + clazz.getPackage().getName() + "." + eb.getServiceModule(".") + ".adapter.repository." + Title + "Repository;");
        list.add("import " + clazz.getPackage().getName() + "." + eb.getServiceModule(".") + ".adapter.repository.po." + Title + "Po;");
        list.add("import " + clazz.getPackage().getName() + "." + eb.getServiceModule(".") + ".domain." + Title + "Domain;");
        list.add("import " + clazz.getPackage().getName() + "." + eb.getServiceModule(".") + ".dto." + Title + "Dto;");
        list.add("import org.springframework.stereotype.Component;");
        if (autoValueField != null) {
            list.add("import org.springframework.transaction.annotation.Transactional;");
        }
        list.add("");
        list.add("import javax.annotation.Resource;");
        list.add("");
        list.add("@Component");
        list.add("public class " + Title + "DomainImpl extends BaseDomainImpl<" + Title + "Dto, " + Title + "Po> implements " + Title + "Domain {");
        list.add("");
        list.add("    @Resource");
        list.add("    private " + Title + "Repository " + title + "Repository;");
        if (autoValueField != null) {
            list.add("    @Resource");
            list.add("    private SequenceService sequenceService;");
        }
        list.add("");
        list.add("    @Override");
        list.add("    public BaseRepository<" + Title + "Po> getMapper() {");
        list.add("        return " + title + "Repository;");
        list.add("    }");
        list.add("");
        list.add("    @Override");
        list.add("    public Class<? extends BaseRepository<" + Title + "Po>> getRepositoryClass() {");
        list.add("        return " + Title + "Repository.class;");
        list.add("    }");
        if (autoValueField != null) {
            ExcelBeanItem ebi = autoValueField.get(1);
            list.add("");
            list.add("    @Transactional");
            list.add("    @Override");
            list.add("    public int save(" + Title + "Dto dto) {");
            list.add("        if (StrUtil.isBlank(dto.get" + StrUtil.upperFirst(StrUtil.toCamelCase(ebi.getColumn())) + "())) {");
            list.add("            String code = sequenceService.genSequence(" + CharPool.DOUBLE_QUOTES + eb.getService() + CharPool.DOUBLE_QUOTES + ", " + CharPool.DOUBLE_QUOTES + Title + "Dto" + CharPool.DOUBLE_QUOTES + ", " + CharPool.DOUBLE_QUOTES + autoValueField.get(0) + CharPool.DOUBLE_QUOTES + ", 4, 1);");
            list.add("            dto.set" + StrUtil.upperFirst(StrUtil.toCamelCase(ebi.getColumn())) + "(code);");
            list.add("        }");
            list.add("        int result = super.save(dto);");
            list.add("        this.checkRepetition(" + CharPool.DOUBLE_QUOTES + StrUtil.toCamelCase(ebi.getColumn()) + CharPool.DOUBLE_QUOTES + ", dto.get" + StrUtil.upperFirst(StrUtil.toCamelCase(ebi.getColumn())) + "());");
            list.add("        return result;");
            list.add("    }");
            list.add("");
            list.add("    @Transactional");
            list.add("    @Override");
            list.add("    public int updateById(" + Title + "Dto dto) {");
            list.add("        int result = super.updateById(dto);");
            list.add("        this.checkRepetition(" + CharPool.DOUBLE_QUOTES + StrUtil.toCamelCase(ebi.getColumn()) + CharPool.DOUBLE_QUOTES + ", dto.get" + StrUtil.upperFirst(StrUtil.toCamelCase(ebi.getColumn())) + "());");
            list.add("        return result;");
            list.add("    }");
        }
        list.add("");
        list.add("}");
        writeFile(file, list);
    }

    private void genService(Map<ConfigType, Boolean> config, ExcelBean eb) {
        String pkg = clazz.getPackage().getName().replaceAll("\\.", "/");
        File dir = new File("src/main/java/" + pkg + "/" + eb.getServiceModule("/") + "/service");
        boolean bool = dir.mkdirs();
        log.trace(String.valueOf(bool));
        String title = StrUtil.toCamelCase(eb.getTitle());
        String Title = StrUtil.upperFirst(title);
        File file = new File(dir.getAbsolutePath() + "/" + Title + "Service.java");
        if (file.exists()) {
            if (checkConfig(config, ConfigType.printExists)) {
                System.out.println("genService:【" + file.getAbsolutePath() + "】 already exist, skipped.");
            }
            return;
        }
        List<String> list = new ArrayList<>();
        list.add("package " + clazz.getPackage().getName() + "." + eb.getServiceModule(".") + ".service;");
        list.add("");
        list.add("import com.peas.platform.framework.mybatisplus.service.BaseService;");
        list.add("import " + clazz.getPackage().getName() + "." + eb.getServiceModule(".") + ".dto." + Title + "Dto;");
        list.add("");
        list.add("public interface " + Title + "Service extends BaseService<" + Title + "Dto> {");
        list.add("");
        list.add("}");
        writeFile(file, list);
    }

    private void genServiceImpl(Map<ConfigType, Boolean> config, ExcelBean eb) {
        String pkg = clazz.getPackage().getName().replaceAll("\\.", "/");
        File dir = new File("src/main/java/" + pkg + "/" + eb.getServiceModule("/") + "/service/impl");
        boolean bool = dir.mkdirs();
        log.trace(String.valueOf(bool));
        String title = StrUtil.toCamelCase(eb.getTitle());
        String Title = StrUtil.upperFirst(title);
        File file = new File(dir.getAbsolutePath() + "/" + Title + "ServiceImpl.java");
        if (file.exists()) {
            if (checkConfig(config, ConfigType.printExists)) {
                System.out.println("genServiceImpl:【" + file.getAbsolutePath() + "】 already exist, skipped.");
            }
            return;
        }
        List<String> list = new ArrayList<>();
        list.add("package " + clazz.getPackage().getName() + "." + eb.getServiceModule(".") + ".service.impl;");
        list.add("");
        list.add("import cn.hutool.core.util.StrUtil;");
        list.add("import com.peas.platform.framework.mybatisplus.domain.BaseDomain;");
        list.add("import com.peas.platform.framework.mybatisplus.po.BasePo;");
        list.add("import com.peas.platform.framework.mybatisplus.service.BaseServiceImpl;");
        list.add("import " + clazz.getPackage().getName() + "." + eb.getServiceModule(".") + ".domain." + Title + "Domain;");
        list.add("import " + clazz.getPackage().getName() + "." + eb.getServiceModule(".") + ".dto." + Title + "Dto;");
        list.add("import " + clazz.getPackage().getName() + "." + eb.getServiceModule(".") + ".service." + Title + "Service;");
        list.add("import org.springframework.stereotype.Service;");
        list.add("");
        list.add("import javax.annotation.Resource;");
        list.add("");
        list.add("@Service");
        list.add("public class " + Title + "ServiceImpl extends BaseServiceImpl<" + Title + "Dto> implements " + Title + "Service {");
        list.add("");
        list.add("    @Resource");
        list.add("    private " + Title + "Domain " + title + "Domain;");
        list.add("");
        list.add("    @Override");
        list.add("    public BaseDomain<" + Title + "Dto, ? extends BasePo> getDomain() {");
        list.add("        return " + title + "Domain;");
        list.add("    }");
        list.add("");
        list.add("}");
        writeFile(file, list);
    }

    private void genVo(Map<ConfigType, Boolean> config, ExcelBean eb) {
        String pkg = clazz.getPackage().getName().replaceAll("\\.", "/");
        File dir = new File("src/main/java/" + pkg + "/" + eb.getServiceModule("/") + "/controller/vo");
        boolean bool = dir.mkdirs();
        log.trace(String.valueOf(bool));
        String title = StrUtil.toCamelCase(eb.getTitle());
        String Title = StrUtil.upperFirst(title);
        File file = new File(dir.getAbsolutePath() + "/" + Title + "Vo.java");
        if (file.exists()) {
            if (checkConfig(config, ConfigType.printExists)) {
                System.out.println("genVo:【" + file.getAbsolutePath() + "】 already exist, skipped.");
            }
            return;
        }
        List<String> list = new ArrayList<>();
        list.add("package " + clazz.getPackage().getName() + "." + eb.getServiceModule(".") + ".controller.vo;");
        list.add("");
        list.add("import java.util.*;");
        list.add("import java.math.*;");
        list.add("import com.peas.platform.common.core.annotation.Comment;");
        list.add("import com.peas.platform.common.core.vo.BaseVo;");
        list.add("import io.swagger.annotations.ApiModel;");
        list.add("import io.swagger.annotations.ApiModelProperty;");
        list.add("import lombok.Data;");
        list.add("import lombok.EqualsAndHashCode;");
        list.add("");
        list.add("import javax.validation.constraints.*;");
        list.add("");
        list.add("@Data");
        list.add("@EqualsAndHashCode(callSuper = false)");
        list.add("@ApiModel(" + CharPool.DOUBLE_QUOTES + eb.getDesc() + CharPool.DOUBLE_QUOTES + ")");
        list.add("public class " + Title + "Vo extends BaseVo {");
        list.add("");
        for (ExcelBeanItem ebi : eb.getList()) {
            if (StrUtil.isBlank(ebi.getColumn())) {
                continue;
            }
            if (StrUtil.isNotBlank(ebi.getRemark())) {
                list.add("    // " + ebi.getRemark().replaceAll("\r\n", ";").replaceAll("\n", ";"));
            }
            String notes = "";
            String str = "";
            if (StrUtil.isNotBlank(ebi.getValueEnum())) {
                notes = ", notes = " + CharPool.DOUBLE_QUOTES + Constants.VALUE_PREFIX_ENUM + ebi.getValueEnum() + CharPool.DOUBLE_QUOTES;
                str = ", enumType = " + CharPool.DOUBLE_QUOTES + ebi.getValueEnum() + CharPool.DOUBLE_QUOTES;
            }
            if (StrUtil.isNotBlank(ebi.getValueDict())) {
                notes = ", notes = " + CharPool.DOUBLE_QUOTES + Constants.VALUE_PREFIX_DICT + ebi.getValueDict() + CharPool.DOUBLE_QUOTES;
                str = ", dictType = " + CharPool.DOUBLE_QUOTES + ebi.getValueDict() + CharPool.DOUBLE_QUOTES;
            }
            if (StrUtil.isNotBlank(ebi.getValueForeign())) {
                notes = ", notes = " + CharPool.DOUBLE_QUOTES + Constants.VALUE_PREFIX_FOREIGN + ebi.getValueForeign() + CharPool.DOUBLE_QUOTES;
                str = ", foreignType = " + CharPool.DOUBLE_QUOTES + ebi.getValueForeign() + CharPool.DOUBLE_QUOTES;
            }
            list.add("    @Comment(value = " + CharPool.DOUBLE_QUOTES + ebi.getName() + CharPool.DOUBLE_QUOTES + str + ")");
            list.add("    @ApiModelProperty(value = " + CharPool.DOUBLE_QUOTES + ebi.getName() + CharPool.DOUBLE_QUOTES + notes + ")");
            switch (ebi.getJdbcType()) {
                case CLOB:
                    if ("否".equals(ebi.getIsnull()))
                        list.add("    @NotBlank(message = " + CharPool.DOUBLE_QUOTES + ebi.getName() + "不能为空" + CharPool.DOUBLE_QUOTES + ")");
                    break;
                case VARCHAR:
                    if ("否".equals(ebi.getIsnull()))
                        list.add("    @NotBlank(message = " + CharPool.DOUBLE_QUOTES + ebi.getName() + "不能为空" + CharPool.DOUBLE_QUOTES + ")");
                    list.add("    @Size(max = " + ebi.getLength() + ", message = " + CharPool.DOUBLE_QUOTES + ebi.getName() + "不能超过" + ebi.getLength() + "个字符" + CharPool.DOUBLE_QUOTES + ")");
                    break;
                case INTEGER:
                    if (ebi.getLength() != null && ebi.getLength() < 9) {
                        int max = 0;
                        for (int i = 0; i < ebi.getLength(); i++) {
                            max += NumberUtil.pow(10, i).intValue() * 9;
                        }
                        list.add("    @Max(value = " + max + ", message = " + CharPool.DOUBLE_QUOTES + ebi.getName() + "取值无效" + CharPool.DOUBLE_QUOTES + ")");
                    }
                case DECIMAL:
                case BIGINT:
                case TIMESTAMP:
                    if ("否".equals(ebi.getIsnull()))
                        list.add("    @NotNull(message = " + CharPool.DOUBLE_QUOTES + ebi.getName() + "不能为空" + CharPool.DOUBLE_QUOTES + ")");
                    break;

            }
            String s = prop(ebi);
            list.add(s);
            list.add("");
        }
        list.add("}");
        writeFile(file, list);
    }

    private void genCriteria(Map<ConfigType, Boolean> config, ExcelBean eb) {
        String pkg = clazz.getPackage().getName().replaceAll("\\.", "/");
        File dir = new File("src/main/java/" + pkg + "/" + eb.getServiceModule("/") + "/controller/criteria");
        boolean bool = dir.mkdirs();
        log.trace(String.valueOf(bool));
        String title = StrUtil.toCamelCase(eb.getTitle());
        String Title = StrUtil.upperFirst(title);
        File file = new File(dir.getAbsolutePath() + "/" + Title + "Criteria.java");
        if (file.exists()) {
            if (checkConfig(config, ConfigType.printExists)) {
                System.out.println("genCriteria:【" + file.getAbsolutePath() + "】 already exist, skipped.");
            }
            return;
        }
        List<String> list = new ArrayList<>();
        list.add("package " + clazz.getPackage().getName() + "." + eb.getServiceModule(".") + ".controller.criteria;");
        list.add("");
        list.add("import " + clazz.getPackage().getName() + "." + eb.getServiceModule(".") + ".controller.vo." + Title + "Vo;");
        list.add("import io.swagger.annotations.ApiModel;");
        list.add("import io.swagger.annotations.ApiModelProperty;");
        list.add("import lombok.Data;");
        list.add("import lombok.EqualsAndHashCode;");
        list.add("");
        list.add("import java.util.Date;");
        list.add("");
        list.add("@Data");
        list.add("@EqualsAndHashCode(callSuper = false)");
        list.add("@ApiModel(" + CharPool.DOUBLE_QUOTES + eb.getDesc() + "查询条件" + CharPool.DOUBLE_QUOTES + ")");
        list.add("public class " + Title + "Criteria extends " + Title + "Vo {");
        list.add("");
        list.add("    @ApiModelProperty(value = " + CharPool.DOUBLE_QUOTES + "创建时间(从)" + CharPool.DOUBLE_QUOTES + ")");
        list.add("    private Date createTime" + Constants.CRITERIA_START + ";");
        list.add("");
        list.add("    @ApiModelProperty(value = " + CharPool.DOUBLE_QUOTES + "创建时间(到)" + CharPool.DOUBLE_QUOTES + ")");
        list.add("    private Date createTime" + Constants.CRITERIA_END + ";");
        list.add("");
        list.add("    @ApiModelProperty(value = " + CharPool.DOUBLE_QUOTES + "最后修改时间(从)" + CharPool.DOUBLE_QUOTES + ")");
        list.add("    private Date updateTime" + Constants.CRITERIA_START + ";");
        list.add("");
        list.add("    @ApiModelProperty(value = " + CharPool.DOUBLE_QUOTES + "最后修改时间(到)" + CharPool.DOUBLE_QUOTES + ")");
        list.add("    private Date updateTime" + Constants.CRITERIA_END + ";");
        list.add("");
        for (ExcelBeanItem ebi : eb.getList()) {
            if (StrUtil.isBlank(ebi.getColumn())) {
                continue;
            }
            if (ebi.getJdbcType() == JDBCType.TIMESTAMP) {
                list.add("    @ApiModelProperty(value = " + CharPool.DOUBLE_QUOTES + ebi.getName() + "(从)" + CharPool.DOUBLE_QUOTES + ")");
                list.add("    private Date" + " " + StrUtil.toCamelCase(ebi.getColumn()) + Constants.CRITERIA_START + ";");
                list.add("    @ApiModelProperty(value = " + CharPool.DOUBLE_QUOTES + ebi.getName() + "(到)" + CharPool.DOUBLE_QUOTES + ")");
                list.add("    private Date" + " " + StrUtil.toCamelCase(ebi.getColumn()) + Constants.CRITERIA_END + ";");
                list.add("");

            }
        }
        list.add("}");
        writeFile(file, list);
    }

    private void genController(Map<ConfigType, Boolean> config, ExcelBean eb) {
        String pkg = clazz.getPackage().getName().replaceAll("\\.", "/");
        File dir = new File("src/main/java/" + pkg + "/" + eb.getServiceModule("/") + "/controller");
        String title = StrUtil.toCamelCase(eb.getTitle());
        String Title = StrUtil.upperFirst(title);
        boolean bool = dir.mkdirs();
        log.trace(String.valueOf(bool));
        File file = new File(dir.getAbsolutePath() + "/" + Title + "Controller.java");
        if (file.exists()) {
            if (checkConfig(config, ConfigType.printExists)) {
                System.out.println("genController:【" + file.getAbsolutePath() + "】 already exist, skipped.");
            }
            return;
        }
        List<String> list = new ArrayList<>();
        list.add("package " + clazz.getPackage().getName() + "." + eb.getServiceModule(".") + ".controller;");
        list.add("");
        list.add("import cn.hutool.core.bean.BeanUtil;");
        list.add("import cn.hutool.core.collection.CollUtil;");
        list.add("import cn.hutool.core.date.DateUtil;");
        list.add("import cn.hutool.core.util.StrUtil;");
        list.add("import cn.hutool.poi.excel.ExcelWriter;");
        list.add("import cn.hutool.poi.excel.RowUtil;");
        list.add("import cn.hutool.poi.excel.WorkbookUtil;");
        list.add("import cn.hutool.poi.excel.cell.CellUtil;");
        list.add("import com.alibaba.fastjson.JSONObject;");
        list.add("import com.baomidou.mybatisplus.extension.plugins.pagination.Page;");
        list.add("import com.peas.platform.common.core.constant.Constants;");
        list.add("import com.peas.platform.common.core.dto.ResponseDto;");
        list.add("import com.peas.platform.common.core.utils.ExcelTool;");
        list.add("import com.peas.platform.common.core.utils.ExceptionUtil;");
        list.add("import com.peas.platform.common.core.utils.ValidatorUtil;");
        list.add("import com.peas.platform.framework.mybatisplus.utils.PageUtil;");
        list.add("import " + clazz.getPackage().getName() + "." + eb.getServiceModule(".") + ".controller.criteria." + Title + "Criteria;");
        list.add("import " + clazz.getPackage().getName() + "." + eb.getServiceModule(".") + ".controller.vo." + Title + "Vo;");
        list.add("import " + clazz.getPackage().getName() + "." + eb.getServiceModule(".") + ".dto." + Title + "Dto;");
        list.add("import " + clazz.getPackage().getName() + "." + eb.getServiceModule(".") + ".service." + Title + "Service;");
        list.add("import io.swagger.annotations.Api;");
        list.add("import io.swagger.annotations.ApiModelProperty;");
        list.add("import io.swagger.annotations.ApiOperation;");
        list.add("import io.swagger.annotations.ApiParam;");
        list.add("import lombok.SneakyThrows;");
        list.add("import org.apache.poi.ss.usermodel.*;");
        list.add("import org.springframework.http.MediaType;");
        list.add("import org.springframework.web.bind.annotation.*;");
        list.add("import org.springframework.web.multipart.MultipartFile;");
        list.add("");
        list.add("import javax.annotation.Resource;");
        list.add("import javax.servlet.http.HttpServletRequest;");
        list.add("import javax.servlet.http.HttpServletResponse;");
        list.add("import javax.validation.Valid;");
        list.add("import javax.validation.constraints.NotBlank;");
        list.add("import javax.validation.constraints.NotNull;");
        list.add("import java.io.Serializable;");
        list.add("import java.lang.reflect.Field;");
        list.add("import java.net.URLEncoder;");
        list.add("import java.nio.charset.StandardCharsets;");
        list.add("import java.util.ArrayList;");
        list.add("import java.util.HashMap;");
        list.add("import java.util.List;");
        list.add("import java.util.Map;");
        list.add("");
        list.add("@Api(tags = " + CharPool.DOUBLE_QUOTES + "【" + eb.getDesc() + "】接口" + CharPool.DOUBLE_QUOTES + ")");
        list.add("@RestController");
        list.add("@RequestMapping(" + CharPool.DOUBLE_QUOTES + "/api/v1/" + StrUtil.toSymbolCase(title, '-') + CharPool.DOUBLE_QUOTES + ")");
        list.add("public class " + Title + "Controller {");
        list.add("");
        list.add("    @Resource");
        list.add("    private HttpServletRequest request;");
        list.add("    @Resource");
        list.add("    private HttpServletResponse response;");
        list.add("    @Resource");
        list.add("    private " + Title + "Service " + title + "Service;");
        list.add("");
        list.add("    @ApiOperation(value = " + CharPool.DOUBLE_QUOTES + "添加" + eb.getDesc() + CharPool.DOUBLE_QUOTES + ")");
        list.add("    @PostMapping(" + CharPool.DOUBLE_QUOTES + "/add" + CharPool.DOUBLE_QUOTES + ")");
        list.add("    public ResponseDto<" + Title + "Dto> add(@RequestBody @Valid " + Title + "Vo " + title + "Vo) {");
        list.add("        " + Title + "Dto dto = BeanUtil.copyProperties(" + title + "Vo, " + Title + "Dto.class);");
        list.add("        " + title + "Service.save(dto);");
        list.add("        return ResponseDto.getSuccessResponseDto(dto);");
        list.add("    }");
        list.add("");
        list.add("    @ApiOperation(value = " + CharPool.DOUBLE_QUOTES + "删除" + eb.getDesc() + CharPool.DOUBLE_QUOTES + ")");
        list.add("    @DeleteMapping(" + CharPool.DOUBLE_QUOTES + "/{id}" + CharPool.DOUBLE_QUOTES + ")");
        list.add("    public ResponseDto<Integer> delete(@ApiParam(name = " + CharPool.DOUBLE_QUOTES + "id" + CharPool.DOUBLE_QUOTES + ", value = " + CharPool.DOUBLE_QUOTES + "要删除的数据主键ID" + CharPool.DOUBLE_QUOTES + ", example = " + CharPool.DOUBLE_QUOTES + "1" + CharPool.DOUBLE_QUOTES + ") @PathVariable(" + CharPool.DOUBLE_QUOTES + "id" + CharPool.DOUBLE_QUOTES + ") Long id) {");
        list.add("        int result = " + title + "Service.removeById(id);");
        list.add("        return ResponseDto.getSuccessResponseDto(result);");
        list.add("    }");
        list.add("");
        list.add("    @ApiOperation(value = " + CharPool.DOUBLE_QUOTES + "修改" + eb.getDesc() + CharPool.DOUBLE_QUOTES + ")");
        list.add("    @PutMapping(" + CharPool.DOUBLE_QUOTES + "/modify" + CharPool.DOUBLE_QUOTES + ")");
        list.add("    public ResponseDto<" + Title + "Dto> modify(@RequestBody @Valid " + Title + "Vo " + title + "Vo) {");
        list.add("        " + Title + "Dto dto = BeanUtil.copyProperties(" + title + "Vo, " + Title + "Dto.class);");
        list.add("        " + title + "Service.updateById(dto);");
        list.add("        return ResponseDto.getSuccessResponseDto(dto);");
        list.add("    }");
        list.add("");
        list.add("    @ApiOperation(value = " + CharPool.DOUBLE_QUOTES + "根据ID查询" + eb.getDesc() + CharPool.DOUBLE_QUOTES + ")");
        list.add("    @GetMapping(" + CharPool.DOUBLE_QUOTES + "/{id}" + CharPool.DOUBLE_QUOTES + ")");
        list.add("    public ResponseDto<" + Title + "Vo> id(@ApiParam(name = " + CharPool.DOUBLE_QUOTES + "id" + CharPool.DOUBLE_QUOTES + ", value = " + CharPool.DOUBLE_QUOTES + "查询的主键ID" + CharPool.DOUBLE_QUOTES + ", example = " + CharPool.DOUBLE_QUOTES + "1" + CharPool.DOUBLE_QUOTES + ") @PathVariable(" + CharPool.DOUBLE_QUOTES + "id" + CharPool.DOUBLE_QUOTES + ") Long id) {");
        list.add("        " + Title + "Dto dto = " + title + "Service.getById(id);");
        list.add("        " + Title + "Vo vo = BeanUtil.copyProperties(dto, " + Title + "Vo.class);");
        list.add("        return ResponseDto.getSuccessResponseDto(vo);");
        list.add("    }");
        list.add("");
        list.add("    @ApiOperation(value = " + CharPool.DOUBLE_QUOTES + "根据多个ID查询" + eb.getDesc() + CharPool.DOUBLE_QUOTES + ")");
        list.add("    @GetMapping(" + CharPool.DOUBLE_QUOTES + "/ids" + CharPool.DOUBLE_QUOTES + ")");
        list.add("    public ResponseDto<List<" + Title + "Vo>> ids(@ApiParam(name = " + CharPool.DOUBLE_QUOTES + "ids" + CharPool.DOUBLE_QUOTES + ", value = " + CharPool.DOUBLE_QUOTES + "查询多个主键的id，用半角逗号分隔" + CharPool.DOUBLE_QUOTES + ", example = " + CharPool.DOUBLE_QUOTES + "1,2,3,4,5" + CharPool.DOUBLE_QUOTES + ") String ids) {");
        list.add("        List<Long> list = new ArrayList<>();");
        list.add("        CollUtil.forEach(StrUtil.split(ids, ','), (CollUtil.Consumer<String>) (id, index) -> list.add(Long.parseLong(id)));");
        list.add("        List<" + Title + "Dto> result = " + title + "Service.listByIds(list);");
        list.add("        List<" + Title + "Vo> r = BeanUtil.copyToList(result, " + Title + "Vo.class);");
        list.add("        return ResponseDto.getSuccessResponseDto(r);");
        list.add("    }");
        list.add("");
        list.add("    @ApiOperation(value = " + CharPool.DOUBLE_QUOTES + "根据某个字段查询" + eb.getDesc() + CharPool.DOUBLE_QUOTES + ")");
        list.add("    @GetMapping(" + CharPool.DOUBLE_QUOTES + "/listByField" + CharPool.DOUBLE_QUOTES + ")");
        list.add("    public ResponseDto<List<" + Title + "Vo>> listByField(@ApiParam(name = " + CharPool.DOUBLE_QUOTES + "field" + CharPool.DOUBLE_QUOTES + ", value = " + CharPool.DOUBLE_QUOTES + "要查询的字段" + CharPool.DOUBLE_QUOTES + ", example = " + CharPool.DOUBLE_QUOTES + "id" + CharPool.DOUBLE_QUOTES + ") String field,");
        list.add("                                                    @ApiParam(name = " + CharPool.DOUBLE_QUOTES + "values" + CharPool.DOUBLE_QUOTES + ", value = " + CharPool.DOUBLE_QUOTES + "字段对应的多个值，用半角逗号分隔" + CharPool.DOUBLE_QUOTES + ", example = " + CharPool.DOUBLE_QUOTES + "1,2,3,4,5" + CharPool.DOUBLE_QUOTES + ") String values) {");
        list.add("        List<String> list = StrUtil.split(values, StrUtil.COMMA);");
        list.add("        List<" + Title + "Dto> result = " + title + "Service.listByField(field, list);");
        list.add("        List<" + Title + "Vo> r = BeanUtil.copyToList(result, " + Title + "Vo.class);");
        list.add("        return ResponseDto.getSuccessResponseDto(r);");
        list.add("    }");
        list.add("");
        list.add("    @ApiOperation(value = " + CharPool.DOUBLE_QUOTES + "根据条件查询" + eb.getDesc() + "（分页）" + CharPool.DOUBLE_QUOTES + ")");
        list.add("    @GetMapping(" + CharPool.DOUBLE_QUOTES + "/page" + CharPool.DOUBLE_QUOTES + ")");
        list.add("    public ResponseDto<Page<" + Title + "Vo>> page(" + Title + "Criteria condition,");
        list.add("                                 @ApiParam(name = " + CharPool.DOUBLE_QUOTES + Constants.PAGE_NUM + CharPool.DOUBLE_QUOTES + ", value = " + CharPool.DOUBLE_QUOTES + "分页页码" + CharPool.DOUBLE_QUOTES + ", example = " + CharPool.DOUBLE_QUOTES + Constants.DEFAULT_PAGE_NUM + CharPool.DOUBLE_QUOTES + ") Integer " + Constants.PAGE_NUM + ",");
        list.add("                                 @ApiParam(name = " + CharPool.DOUBLE_QUOTES + Constants.PAGE_SIZE + CharPool.DOUBLE_QUOTES + ", value = " + CharPool.DOUBLE_QUOTES + "分页每页大小" + CharPool.DOUBLE_QUOTES + ", example = " + CharPool.DOUBLE_QUOTES + Constants.DEFAULT_PAGE_SIZE + CharPool.DOUBLE_QUOTES + ") Integer " + Constants.PAGE_SIZE + ",");
        list.add("                                 @ApiParam(name = " + CharPool.DOUBLE_QUOTES + Constants.SORT_FIELD + CharPool.DOUBLE_QUOTES + ", value = " + CharPool.DOUBLE_QUOTES + "排序字段" + CharPool.DOUBLE_QUOTES + ", example = " + CharPool.DOUBLE_QUOTES + Constants.DEFAULT_SORT_FIELD + CharPool.DOUBLE_QUOTES + ") String " + Constants.SORT_FIELD + ",");
        list.add("                                 @ApiParam(name = " + CharPool.DOUBLE_QUOTES + Constants.SORT_TYPE + CharPool.DOUBLE_QUOTES + ", value = " + CharPool.DOUBLE_QUOTES + "排序方式" + CharPool.DOUBLE_QUOTES + ", example = " + CharPool.DOUBLE_QUOTES + Constants.SORT_DESC + CharPool.DOUBLE_QUOTES + ") String " + Constants.SORT_TYPE + ") {");
        list.add("        Page<" + Title + "Dto> pager = PageUtil.genPager(" + Constants.PAGE_NUM + ", " + Constants.PAGE_SIZE + ", " + Constants.SORT_FIELD + ", " + Constants.SORT_TYPE + ");");
        list.add("        " + Title + "Dto c = BeanUtil.copyProperties(condition, " + Title + "Dto.class);");
        list.add("        Page<" + Title + "Dto> page = " + title + "Service.page(pager, c);");
        list.add("        Page<" + Title + "Vo> vos = PageUtil.copyPage(page, " + Title + "Vo.class);");
        list.add("        return ResponseDto.getSuccessResponseDto(vos);");
        list.add("    }");
        list.add("");
        list.add("    @ApiOperation(value = " + CharPool.DOUBLE_QUOTES + "根据条件搜索" + eb.getDesc() + "（分页）" + CharPool.DOUBLE_QUOTES + ")");
        list.add("    @GetMapping(" + CharPool.DOUBLE_QUOTES + "/search" + CharPool.DOUBLE_QUOTES + ")");
        list.add("    public ResponseDto<Page<" + Title + "Vo>> search(" + Title + "Criteria condition,");
        list.add("                                 @ApiParam(name = " + CharPool.DOUBLE_QUOTES + Constants.PAGE_NUM + CharPool.DOUBLE_QUOTES + ", value = " + CharPool.DOUBLE_QUOTES + "分页页码" + CharPool.DOUBLE_QUOTES + ", example = " + CharPool.DOUBLE_QUOTES + Constants.DEFAULT_PAGE_NUM + CharPool.DOUBLE_QUOTES + ") Integer " + Constants.PAGE_NUM + ",");
        list.add("                                 @ApiParam(name = " + CharPool.DOUBLE_QUOTES + Constants.PAGE_SIZE + CharPool.DOUBLE_QUOTES + ", value = " + CharPool.DOUBLE_QUOTES + "分页每页大小" + CharPool.DOUBLE_QUOTES + ", example = " + CharPool.DOUBLE_QUOTES + Constants.DEFAULT_PAGE_SIZE + CharPool.DOUBLE_QUOTES + ") Integer " + Constants.PAGE_SIZE + ",");
        list.add("                                 @ApiParam(name = " + CharPool.DOUBLE_QUOTES + Constants.SORT_FIELD + CharPool.DOUBLE_QUOTES + ", value = " + CharPool.DOUBLE_QUOTES + "排序字段" + CharPool.DOUBLE_QUOTES + ", example = " + CharPool.DOUBLE_QUOTES + Constants.DEFAULT_SORT_FIELD + CharPool.DOUBLE_QUOTES + ") String " + Constants.SORT_FIELD + ",");
        list.add("                                 @ApiParam(name = " + CharPool.DOUBLE_QUOTES + Constants.SORT_TYPE + CharPool.DOUBLE_QUOTES + ", value = " + CharPool.DOUBLE_QUOTES + "排序方式" + CharPool.DOUBLE_QUOTES + ", example = " + CharPool.DOUBLE_QUOTES + Constants.SORT_DESC + CharPool.DOUBLE_QUOTES + ") String " + Constants.SORT_TYPE + ") {");
        list.add("        Page<" + Title + "Dto> pager = PageUtil.genPager(" + Constants.PAGE_NUM + ", " + Constants.PAGE_SIZE + ", " + Constants.SORT_FIELD + ", " + Constants.SORT_TYPE + ");");
        list.add("        Map<String, Object> c = BeanUtil.beanToMap(condition);");
        list.add("        Page<" + Title + "Dto> page = " + title + "Service.page(pager, c);");
        list.add("        Page<" + Title + "Vo> vos = PageUtil.copyPage(page, " + Title + "Vo.class);");
        list.add("        return ResponseDto.getSuccessResponseDto(vos);");
        list.add("    }");
        list.add("");
        list.add("    @SneakyThrows");
        list.add("    @ApiOperation(value = " + CharPool.DOUBLE_QUOTES + "根据条件导出" + eb.getDesc() + CharPool.DOUBLE_QUOTES + ")");
        list.add("    @GetMapping(" + CharPool.DOUBLE_QUOTES + "/export" + CharPool.DOUBLE_QUOTES + ")");
        list.add("    public void export(" + Title + "Criteria condition) {");
        list.add("        try {");
        list.add("            assert request != null;");
        list.add("            " + Title + "Dto c = BeanUtil.copyProperties(condition, " + Title + "Dto.class);");
        list.add("            List<" + Title + "Dto> page = " + title + "Service.list(c);");
        list.add("            String file = " + CharPool.DOUBLE_QUOTES + "导出" + eb.getDesc() + "-" + CharPool.DOUBLE_QUOTES + " + DateUtil.today() + " + CharPool.DOUBLE_QUOTES + ".xlsx" + CharPool.DOUBLE_QUOTES + ";");
        list.add("            String name = URLEncoder.encode(file, StandardCharsets.UTF_8.name());");
        list.add("            List<String> head = new ArrayList<>();");
        list.add("            head.add(" + CharPool.DOUBLE_QUOTES + "ID" + CharPool.DOUBLE_QUOTES + ");");
        list.add("            for (Field f : " + Title + "Vo.class.getDeclaredFields()) {");
        list.add("                f.setAccessible(true);");
        list.add("                ApiModelProperty amp = f.getAnnotation(ApiModelProperty.class);");
        list.add("                if (amp != null) {");
        list.add("                    head.add(amp.value());");
        list.add("                }");
        list.add("            }");
        list.add("            head.add(" + CharPool.DOUBLE_QUOTES + "创建时间" + CharPool.DOUBLE_QUOTES + ");");
        list.add("            head.add(" + CharPool.DOUBLE_QUOTES + "最后修改时间" + CharPool.DOUBLE_QUOTES + ");");
        list.add("            List<List<?>> data = new ArrayList<>();");
        list.add("            if (CollUtil.isNotEmpty(page)) {");
        list.add("                for (" + Title + "Dto dto : page) {");
        list.add("                    " + Title + "Vo vo = BeanUtil.copyProperties(dto, " + Title + "Vo.class);");
        list.add("                    List<Serializable> row = new ArrayList<>();");
        list.add("                    row.add(String.valueOf(dto.getId()));");
        list.add("                    for (Field f : " + Title + "Vo.class.getDeclaredFields()) {");
        list.add("                        f.setAccessible(true);");
        list.add("                        ApiModelProperty amp = f.getAnnotation(ApiModelProperty.class);");
        list.add("                        if (amp != null) {");
        list.add("                            String v = ExcelTool.convertValue(f.get(vo), amp);");
        list.add("                            row.add(v);");
        list.add("                        }");
        list.add("                    }");
        list.add("                    row.add(DateUtil.formatDateTime(dto.getCreateTime()));");
        list.add("                    row.add(DateUtil.formatDateTime(dto.getUpdateTime()));");
        list.add("                    data.add(row);");
        list.add("                }");
        list.add("            }");
        list.add("            try (ExcelWriter writer = ExcelTool.genExcelWriter(head, data)) {");
        list.add("                response.setHeader(" + CharPool.DOUBLE_QUOTES + "Content-disposition" + CharPool.DOUBLE_QUOTES + ", " + CharPool.DOUBLE_QUOTES + "attachment; filename=" + CharPool.DOUBLE_QUOTES + " + name);");
        list.add("                response.setCharacterEncoding(StandardCharsets.UTF_8.name());");
        list.add("                response.setContentType(" + CharPool.DOUBLE_QUOTES + "application/vnd.ms-excel;charset=utf-8" + CharPool.DOUBLE_QUOTES + ");");
        list.add("                writer.flush(response.getOutputStream(), true);");
        list.add("            }");
        list.add("        } catch (Exception e) {");
        list.add("            response.setContentType(new MediaType(MediaType.APPLICATION_JSON, StandardCharsets.UTF_8).toString());");
        list.add("            throw e;");
        list.add("        }");
        list.add("    }");
        list.add("");
        list.add("    @SneakyThrows");
        list.add("    @ApiOperation(value = " + CharPool.DOUBLE_QUOTES + eb.getDesc() + "导入模版下载" + CharPool.DOUBLE_QUOTES + ")");
        list.add("    @GetMapping(" + CharPool.DOUBLE_QUOTES + "/downloadTemplate" + CharPool.DOUBLE_QUOTES + ")");
        list.add("    public void downloadTemplate() {");
        list.add("        try {");
        list.add("            assert request != null;");
        list.add("            String file = " + CharPool.DOUBLE_QUOTES + eb.getDesc() + "导入模版-" + CharPool.DOUBLE_QUOTES + " + DateUtil.today() + " + CharPool.DOUBLE_QUOTES + ".xlsx" + CharPool.DOUBLE_QUOTES + ";");
        list.add("            String name = URLEncoder.encode(file, StandardCharsets.UTF_8.name());");
        list.add("            List<String> head = new ArrayList<>();");
        list.add("            for (Field f : " + Title + "Vo.class.getDeclaredFields()) {");
        list.add("                f.setAccessible(true);");
        list.add("                ApiModelProperty amp = f.getAnnotation(ApiModelProperty.class);");
        list.add("                NotBlank notBlank = f.getAnnotation(NotBlank.class);");
        list.add("                NotNull notNull = f.getAnnotation(NotNull.class);");
        list.add("                if (amp != null) {");
        list.add("                    String label = amp.value();");
        list.add("                    if (notBlank != null || notNull != null) {");
        list.add("                        label = " + CharPool.DOUBLE_QUOTES + "*" + CharPool.DOUBLE_QUOTES + " + label;");
        list.add("                    }");
        list.add("                    head.add(label);");
        list.add("                }");
        list.add("            }");
        list.add("            try (ExcelWriter writer = ExcelTool.genExcelWriter(head, new ArrayList<>())) {");
        list.add("                response.setHeader(" + CharPool.DOUBLE_QUOTES + "Content-disposition" + CharPool.DOUBLE_QUOTES + ", " + CharPool.DOUBLE_QUOTES + "attachment; filename=" + CharPool.DOUBLE_QUOTES + " + name);");
        list.add("                response.setCharacterEncoding(StandardCharsets.UTF_8.name());");
        list.add("                response.setContentType(" + CharPool.DOUBLE_QUOTES + "application/vnd.ms-excel;charset=utf-8" + CharPool.DOUBLE_QUOTES + ");");
        list.add("                writer.flush(response.getOutputStream(), true);");
        list.add("            }");
        list.add("        } catch (Exception e) {");
        list.add("            response.setContentType(new MediaType(MediaType.APPLICATION_JSON, StandardCharsets.UTF_8).toString());");
        list.add("            throw e;");
        list.add("        }");
        list.add("    }");
        list.add("");
        list.add("    @SneakyThrows");
        list.add("    @ApiOperation(value = " + CharPool.DOUBLE_QUOTES + "导入" + eb.getDesc() + "数据" + CharPool.DOUBLE_QUOTES + ")");
        list.add("    @GetMapping(" + CharPool.DOUBLE_QUOTES + "/importData" + CharPool.DOUBLE_QUOTES + ")");
        list.add("    public ResponseDto<JSONObject> importData(@ApiParam(name = " + CharPool.DOUBLE_QUOTES + "file" + CharPool.DOUBLE_QUOTES + ", required = true, value = " + CharPool.DOUBLE_QUOTES + "文件" + CharPool.DOUBLE_QUOTES + ") @RequestPart(value = " + CharPool.DOUBLE_QUOTES + "file" + CharPool.DOUBLE_QUOTES + ") MultipartFile file) {");
        list.add("        Workbook book = WorkbookUtil.createBook(file.getInputStream());");
        list.add("        Sheet sheet = WorkbookUtil.getOrCreateSheet(book, 0);");
        list.add("        Font errFont = book.createFont();");
        list.add("        errFont.setColor(Font.COLOR_RED);");
        list.add("        CellStyle errStyle = book.createCellStyle();");
        list.add("        errStyle.setFont(errFont);");
        list.add("        int rowNums = 0;");
        list.add("        int failed = 0;");
        list.add("        Field[] fields = " + Title + "Vo.class.getDeclaredFields();");
        list.add("        JSONObject res = new JSONObject();");
        list.add("        Map<Integer, String> result = new HashMap<>();");
        list.add("        for (int line = 1; line < sheet.getPhysicalNumberOfRows(); line++) {");
        list.add("            rowNums++;");
        list.add("            Row row = RowUtil.getOrCreateRow(sheet, line);");
        list.add("            Cell errCell = CellUtil.getOrCreateCell(row, fields.length);");
        list.add("            try {");
        list.add("                " + Title + "Dto o = new " + Title + "Dto();");
        list.add("                int i = 0;");
        list.add("                while (i < fields.length) {");
        list.add("                    Field f = fields[i];");
        list.add("                    f.setAccessible(true);");
        list.add("                    ApiModelProperty amp = f.getAnnotation(ApiModelProperty.class);");
        list.add("                    if (amp != null) {");
        list.add("                        String v = Constants.df.formatCellValue(CellUtil.getOrCreateCell(row, i));");
        list.add("                        ValidatorUtil.checkFieldValue(f, v, amp.value());");
        list.add("                        f.set(o, v);");
        list.add("                        i++;");
        list.add("                    }");
        list.add("                }");
        list.add("                " + title + "Service.save(o);");
        list.add("                result.put(line, " + CharPool.DOUBLE_QUOTES + "导入成功" + CharPool.DOUBLE_QUOTES + ");");
        list.add("            } catch (Throwable e) {");
        list.add("                ResponseDto<String> r = ExceptionUtil.render(e);");
        list.add("                errCell.setCellStyle(errStyle);");
        list.add("                errCell.setCellValue(r.getMessage());");
        list.add("                failed++;");
        list.add("                result.put(line, r.getMessage());");
        list.add("            }");
        list.add("        }");
        list.add("        res.put(" + CharPool.DOUBLE_QUOTES + "total" + CharPool.DOUBLE_QUOTES + ", rowNums);");
        list.add("        res.put(" + CharPool.DOUBLE_QUOTES + "success" + CharPool.DOUBLE_QUOTES + ", rowNums - failed);");
        list.add("        res.put(" + CharPool.DOUBLE_QUOTES + "failure" + CharPool.DOUBLE_QUOTES + ", failed);");
        list.add("        res.put(" + CharPool.DOUBLE_QUOTES + "result" + CharPool.DOUBLE_QUOTES + ", result);");
        list.add("        return ResponseDto.getSuccessResponseDto(res);");
        list.add("    }");
        list.add("");
        list.add("}");
        writeFile(file, list);
    }

    private void genVue(Map<ConfigType, Boolean> config, ExcelBean eb) {
        String resourceCode = "";// TODO "A00001";
        String title = StrUtil.toCamelCase(eb.getTitle());
        String Title = StrUtil.upperFirst(title);
        assert Title != null;
        File dir = new File("doc/views/" + eb.getServiceModule("/") + "/" + title);
        boolean bool = dir.mkdirs();
        log.trace(String.valueOf(bool));
        File file = new File(dir.getAbsolutePath() + "/index.vue");
        if (file.exists()) {
            if (checkConfig(config, ConfigType.printExists)) {
                System.out.println("genVue:【" + file.getAbsolutePath() + "】 already exist, skipped.");
            }
            return;
        }
        List<String> list = new ArrayList<>();
        list.add("<template>");
        list.add("  <div class=" + CharPool.DOUBLE_QUOTES + "app-container" + CharPool.DOUBLE_QUOTES + ">");
        list.add("    <el-row :gutter=\"20\">");
        list.add("      <el-col :span=\"24\" class=\"custom-title-box\">");
        list.add("        <div class=\"custom-info-title\">");
        list.add("          {{getTitleByName(nameOfPermission)}}列表查询");
        list.add("          <el-button link @click=\"delFav()\" style=\"margin-bottom: 5px;\" v-if=\"userFavorites?.length > 0\">");
        list.add("            <svg-icon icon-class=\"stars\" color=\"#E6A23C\" />");
        list.add("          </el-button>");
        list.add("          <el-button link @click=\"addFav()\" style=\"margin-bottom: 5px;\" v-else>");
        list.add("            <svg-icon icon-class=\"star\" />");
        list.add("          </el-button>");
        list.add("        </div>");
        list.add("        <div>");
        list.add("          <el-button v-waves type=\"success\" icon=\"Search\" @click=\"handleFilter\">");
        list.add("            查询");
        list.add("          </el-button>");
        list.add("          <el-button icon=\"Refresh\" @click=\"handleResetQuery\">");
        list.add("            重置");
        list.add("          </el-button>");
        list.add("        </div>");
        list.add("      </el-col>");
        list.add("    </el-row>");
        list.add("    <div class=" + CharPool.DOUBLE_QUOTES + "filter-container" + CharPool.DOUBLE_QUOTES + ">");
        list.add("      <el-form :inline=" + CharPool.DOUBLE_QUOTES + "true" + CharPool.DOUBLE_QUOTES + " ref=" + CharPool.DOUBLE_QUOTES + "listQuery" + CharPool.DOUBLE_QUOTES + " :model=" + CharPool.DOUBLE_QUOTES + "listQuery" + CharPool.DOUBLE_QUOTES + " class=" + CharPool.DOUBLE_QUOTES + "demo-form-inline" + CharPool.DOUBLE_QUOTES + ">");
        for (ExcelBeanItem ebi : eb.getList()) {
            String c = StrUtil.toCamelCase(ebi.getColumn().toLowerCase());
            switch (ebi.getJdbcType()) {
                case CLOB:
                    break;
                case VARCHAR:
                    if (StrUtil.isNotBlank(ebi.getValueEnum())) {
                        list.add("        <el-form-item prop=" + CharPool.DOUBLE_QUOTES + c + CharPool.DOUBLE_QUOTES + " label=" + CharPool.DOUBLE_QUOTES + ebi.getName() + CharPool.DOUBLE_QUOTES + ">");
                        list.add("          <el-radio-group v-model=" + CharPool.DOUBLE_QUOTES + "listQuery." + c + CharPool.DOUBLE_QUOTES + ">");
                        list.add("            <el-radio-button label=" + CharPool.DOUBLE_QUOTES + CharPool.DOUBLE_QUOTES + " key=" + CharPool.DOUBLE_QUOTES + CharPool.DOUBLE_QUOTES + ">全部</el-radio-button>");
                        list.add("            <el-radio-button v-for=" + CharPool.DOUBLE_QUOTES + "(item,index) in getEnumList('" + ebi.getValueEnum() + "')" + CharPool.DOUBLE_QUOTES + " :label=" + CharPool.DOUBLE_QUOTES + "item.key" + CharPool.DOUBLE_QUOTES + " :key=" + CharPool.DOUBLE_QUOTES + "index" + CharPool.DOUBLE_QUOTES + ">{{item.value}}</el-radio-button>");
                        list.add("          </el-radio-group>");
                        list.add("        </el-form-item>");
                        break;
                    } else if (StrUtil.isNotBlank(ebi.getValueDict())) {
                        list.add("        <el-form-item prop=" + CharPool.DOUBLE_QUOTES + c + CharPool.DOUBLE_QUOTES + " label=" + CharPool.DOUBLE_QUOTES + ebi.getName() + "(数据字典)" + CharPool.DOUBLE_QUOTES + ">");
                        list.add("          <el-select v-model=" + CharPool.DOUBLE_QUOTES + "listQuery." + c + CharPool.DOUBLE_QUOTES + " class=" + CharPool.DOUBLE_QUOTES + "m-2" + CharPool.DOUBLE_QUOTES + " placeholder=" + CharPool.DOUBLE_QUOTES + "请选择" + CharPool.DOUBLE_QUOTES + ">");
                        list.add("            <el-option key=" + CharPool.DOUBLE_QUOTES + CharPool.DOUBLE_QUOTES + " label=" + CharPool.DOUBLE_QUOTES + "全部" + CharPool.DOUBLE_QUOTES + " value=" + CharPool.DOUBLE_QUOTES + CharPool.DOUBLE_QUOTES + " />");
                        list.add("            <el-option v-for=" + CharPool.DOUBLE_QUOTES + "item in getDictList('" + ebi.getValueDict() + "')" + CharPool.DOUBLE_QUOTES + " :key=" + CharPool.DOUBLE_QUOTES + "item.key" + CharPool.DOUBLE_QUOTES + " :label=" + CharPool.DOUBLE_QUOTES + "`${item.key} - ${item.value}`" + CharPool.DOUBLE_QUOTES + " :value=" + CharPool.DOUBLE_QUOTES + "item.key" + CharPool.DOUBLE_QUOTES + " />");
                        list.add("          </el-select>");
                        list.add("        </el-form-item>");
                        break;
                    } else if (StrUtil.isNotBlank(ebi.getValueForeign())) {
                        //TODO
                    } else if (Arrays.asList("1", "是", "true", "y", "yes").contains(ebi.getIsAccurate())) {
                        list.add("        <el-form-item prop=" + CharPool.DOUBLE_QUOTES + c + CharPool.DOUBLE_QUOTES + " label=" + CharPool.DOUBLE_QUOTES + ebi.getName() + CharPool.DOUBLE_QUOTES + ">");
                        list.add("          <InputTagDialog v-model=" + CharPool.DOUBLE_QUOTES + "listQuery." + c + CharPool.DOUBLE_QUOTES + " placeholder=" + CharPool.DOUBLE_QUOTES + ebi.getName() + CharPool.DOUBLE_QUOTES + " title=" + CharPool.DOUBLE_QUOTES + "填写" + ebi.getName() + CharPool.DOUBLE_QUOTES + " />");
                        list.add("        </el-form-item>");
                    } else {
                        list.add("        <el-form-item prop=" + CharPool.DOUBLE_QUOTES + c + CharPool.DOUBLE_QUOTES + " label=" + CharPool.DOUBLE_QUOTES + ebi.getName() + CharPool.DOUBLE_QUOTES + ">");
                        list.add("          <el-input v-model=" + CharPool.DOUBLE_QUOTES + "listQuery." + c + CharPool.DOUBLE_QUOTES + " placeholder=" + CharPool.DOUBLE_QUOTES + ebi.getName() + CharPool.DOUBLE_QUOTES + " @keyup.enter=" + CharPool.DOUBLE_QUOTES + "handleFilter" + CharPool.DOUBLE_QUOTES + " />");
                        list.add("        </el-form-item>");
                    }
                    break;
                case DECIMAL:
                case BIGINT:
                case INTEGER:
                    list.add("        <el-form-item prop=" + CharPool.DOUBLE_QUOTES + c + CharPool.DOUBLE_QUOTES + " label=" + CharPool.DOUBLE_QUOTES + ebi.getName() + CharPool.DOUBLE_QUOTES + ">");
                    list.add("          <el-input v-model=" + CharPool.DOUBLE_QUOTES + "listQuery." + c + CharPool.DOUBLE_QUOTES + " placeholder=" + CharPool.DOUBLE_QUOTES + ebi.getName() + CharPool.DOUBLE_QUOTES + " @keyup.enter=" + CharPool.DOUBLE_QUOTES + "handleFilter" + CharPool.DOUBLE_QUOTES + " />");
                    list.add("        </el-form-item>");
                    break;
                case TIMESTAMP:
                    list.add("        <el-form-item label=" + CharPool.DOUBLE_QUOTES + ebi.getName() + CharPool.DOUBLE_QUOTES + ">");
                    list.add("          <el-date-picker v-model=" + CharPool.DOUBLE_QUOTES + "listQuery." + c + "Range" + CharPool.DOUBLE_QUOTES);
                    list.add("                          value-format=" + CharPool.DOUBLE_QUOTES + "YYYY-MM-DD HH:mm:ss" + CharPool.DOUBLE_QUOTES);
                    list.add("                          type=" + CharPool.DOUBLE_QUOTES + "datetimerange" + CharPool.DOUBLE_QUOTES);
                    list.add("                          range-separator=" + CharPool.DOUBLE_QUOTES + "-" + CharPool.DOUBLE_QUOTES);
                    list.add("                          start-placeholder=" + CharPool.DOUBLE_QUOTES + ebi.getName() + "(从)" + CharPool.DOUBLE_QUOTES);
                    list.add("                          end-placeholder=" + CharPool.DOUBLE_QUOTES + ebi.getName() + "(到)" + CharPool.DOUBLE_QUOTES + " />");
                    list.add("        </el-form-item>");
                    break;
            }
        }
//        list.add("        <el-form-item>");
//        list.add("          <el-button v-waves type=" + CharPool.DOUBLE_QUOTES + "success" + CharPool.DOUBLE_QUOTES + " icon=" + CharPool.DOUBLE_QUOTES + "Search" + CharPool.DOUBLE_QUOTES + " @click=" + CharPool.DOUBLE_QUOTES + "handleFilter" + CharPool.DOUBLE_QUOTES + ">");
//        list.add("            查询");
//        list.add("          </el-button>");
//        list.add("          <el-button icon=" + CharPool.DOUBLE_QUOTES + "Refresh" + CharPool.DOUBLE_QUOTES + " @click=" + CharPool.DOUBLE_QUOTES + "handleResetQuery" + CharPool.DOUBLE_QUOTES + ">");
//        list.add("            重置");
//        list.add("          </el-button>");
//        list.add("          <el-button v-show=" + CharPool.DOUBLE_QUOTES + "checkAuthByCode('" + resourceCode + "')" + CharPool.DOUBLE_QUOTES + " type=" + CharPool.DOUBLE_QUOTES + "primary" + CharPool.DOUBLE_QUOTES + " icon=" + CharPool.DOUBLE_QUOTES + "Edit" + CharPool.DOUBLE_QUOTES + " @click=" + CharPool.DOUBLE_QUOTES + "handleAdd" + CharPool.DOUBLE_QUOTES + ">");
//        list.add("            新增");
//        list.add("          </el-button>");
//        list.add("          <el-button v-show=" + CharPool.DOUBLE_QUOTES + "checkAuthByCode('" + resourceCode + "')" + CharPool.DOUBLE_QUOTES + " type=" + CharPool.DOUBLE_QUOTES + "primary" + CharPool.DOUBLE_QUOTES + " icon=" + CharPool.DOUBLE_QUOTES + "Download" + CharPool.DOUBLE_QUOTES + " @click=" + CharPool.DOUBLE_QUOTES + "handleExport" + CharPool.DOUBLE_QUOTES + ">");
//        list.add("            导出");
//        list.add("          </el-button>");
//        list.add("        </el-form-item>");
        list.add("      </el-form>");
        list.add("    </div>");
        list.add("    <el-row :gutter=\"20\">");
        list.add("      <el-col :span=\"24\" class=\"custom-title-box\">");
        list.add("        <div class=\"custom-info-title\">列表详情</div>");
        list.add("        <div>");
        list.add("          <el-button v-show=\"checkAuthByCode('')\" type=\"primary\" icon=\"Download\" @click=\"handleExport\">");
        list.add("            导出");
        list.add("          </el-button>");
        list.add("          <el-button type=\"primary\" icon=\"Edit\" :disabled=\"!checkAuthByCode('')\" @click=\"handleAdd\">");
        list.add("            新增");
        list.add("          </el-button>");
        list.add("        </div>");
        list.add("      </el-col>");
        list.add("    </el-row>");
        list.add("    <el-divider class=" + CharPool.DOUBLE_QUOTES + "el-divider--horizontal-margin" + CharPool.DOUBLE_QUOTES + " />");
        list.add("    <el-table v-loading=" + CharPool.DOUBLE_QUOTES + "listLoading" + CharPool.DOUBLE_QUOTES);
        list.add("              :key=" + CharPool.DOUBLE_QUOTES + "tableKey" + CharPool.DOUBLE_QUOTES);
        list.add("              :data=" + CharPool.DOUBLE_QUOTES + "list" + CharPool.DOUBLE_QUOTES);
        list.add("              :row-style=" + CharPool.DOUBLE_QUOTES + "{height: '0'}" + CharPool.DOUBLE_QUOTES);
        list.add("              :cell-style=" + CharPool.DOUBLE_QUOTES + "{padding: '0'}" + CharPool.DOUBLE_QUOTES);
        list.add("              border");
        list.add("              fit");
        list.add("              highlight-current-row");
        list.add("              tooltip-effect=" + CharPool.DOUBLE_QUOTES + "dark" + CharPool.DOUBLE_QUOTES);
        list.add("              @sort-change=" + CharPool.DOUBLE_QUOTES + "handleSortChange" + CharPool.DOUBLE_QUOTES);
        list.add("              @selection-change=" + CharPool.DOUBLE_QUOTES + "handleSelectionChange" + CharPool.DOUBLE_QUOTES + ">");
        list.add("      <el-table-column type=" + CharPool.DOUBLE_QUOTES + "selection" + CharPool.DOUBLE_QUOTES + " width=" + CharPool.DOUBLE_QUOTES + "39px" + CharPool.DOUBLE_QUOTES + " />");
        list.add("      <el-table-column align=" + CharPool.DOUBLE_QUOTES + "center" + CharPool.DOUBLE_QUOTES + " type=" + CharPool.DOUBLE_QUOTES + "index" + CharPool.DOUBLE_QUOTES + " label=" + CharPool.DOUBLE_QUOTES + "序号" + CharPool.DOUBLE_QUOTES + " width=" + CharPool.DOUBLE_QUOTES + "60px" + CharPool.DOUBLE_QUOTES + " />");
        list.add("      <el-table-column v-if=" + CharPool.DOUBLE_QUOTES + "isDebug" + CharPool.DOUBLE_QUOTES + " align=" + CharPool.DOUBLE_QUOTES + "center" + CharPool.DOUBLE_QUOTES + " label=" + CharPool.DOUBLE_QUOTES + "ID" + CharPool.DOUBLE_QUOTES + " prop=" + CharPool.DOUBLE_QUOTES + "id" + CharPool.DOUBLE_QUOTES + " width=" + CharPool.DOUBLE_QUOTES + "60px" + CharPool.DOUBLE_QUOTES + " sortable show-overflow-tooltip />");
        for (ExcelBeanItem ebi : eb.getList()) {
            String c = StrUtil.toCamelCase(ebi.getColumn().toLowerCase());
            switch (ebi.getJdbcType()) {
                case CLOB:
                    list.add("      <el-table-column align=" + CharPool.DOUBLE_QUOTES + "center" + CharPool.DOUBLE_QUOTES + " label=" + CharPool.DOUBLE_QUOTES + ebi.getName() + CharPool.DOUBLE_QUOTES + " prop=" + CharPool.DOUBLE_QUOTES + c + CharPool.DOUBLE_QUOTES + " min-width=" + CharPool.DOUBLE_QUOTES + "200px" + CharPool.DOUBLE_QUOTES + " show-overflow-tooltip />");
                    break;
                case VARCHAR:
                    if (StrUtil.isNotBlank(ebi.getValueEnum())) {
                        list.add("      <el-table-column align=" + CharPool.DOUBLE_QUOTES + "center" + CharPool.DOUBLE_QUOTES + " label=" + CharPool.DOUBLE_QUOTES + ebi.getName() + CharPool.DOUBLE_QUOTES + " prop=" + CharPool.DOUBLE_QUOTES + c + CharPool.DOUBLE_QUOTES + " min-width=" + CharPool.DOUBLE_QUOTES + calcColumnWidth(ebi.getName()) + "px" + CharPool.DOUBLE_QUOTES + " sortable show-overflow-tooltip>");
                        list.add("        <template v-slot=" + CharPool.DOUBLE_QUOTES + "{row}" + CharPool.DOUBLE_QUOTES + ">{{ getEnumKeyLabel('" + ebi.getValueEnum() + "', row." + c + ") }}</template>");
                        list.add("      </el-table-column>");
                    } else if (StrUtil.isNotBlank(ebi.getValueDict())) {
                        list.add("      <el-table-column align=" + CharPool.DOUBLE_QUOTES + "center" + CharPool.DOUBLE_QUOTES + " label=" + CharPool.DOUBLE_QUOTES + ebi.getName() + CharPool.DOUBLE_QUOTES + " prop=" + CharPool.DOUBLE_QUOTES + c + CharPool.DOUBLE_QUOTES + " min-width=" + CharPool.DOUBLE_QUOTES + calcColumnWidth(ebi.getName()) + "px" + CharPool.DOUBLE_QUOTES + " sortable show-overflow-tooltip>");
                        list.add("        <template v-slot=" + CharPool.DOUBLE_QUOTES + "{row}" + CharPool.DOUBLE_QUOTES + ">{{ getDictKeyLabel('" + ebi.getValueDict() + "', row." + c + ") }}</template>");
                        list.add("      </el-table-column>");
                    } else if (StrUtil.isNotBlank(ebi.getValueForeign())) {
                        //TODO
                    } else {
                        list.add("      <el-table-column align=" + CharPool.DOUBLE_QUOTES + "center" + CharPool.DOUBLE_QUOTES + " label=" + CharPool.DOUBLE_QUOTES + ebi.getName() + CharPool.DOUBLE_QUOTES + " prop=" + CharPool.DOUBLE_QUOTES + c + CharPool.DOUBLE_QUOTES + " min-width=" + CharPool.DOUBLE_QUOTES + calcColumnWidth(ebi.getName()) + "px" + CharPool.DOUBLE_QUOTES + " sortable show-overflow-tooltip>");
                        list.add("        <template v-slot=" + CharPool.DOUBLE_QUOTES + "{row}" + CharPool.DOUBLE_QUOTES + ">{{ row." + c + " }}</template>");
                        list.add("      </el-table-column>");
                    }
                    break;
                case DECIMAL:
                case BIGINT:
                case INTEGER:
                    list.add("      <el-table-column align=" + CharPool.DOUBLE_QUOTES + "center" + CharPool.DOUBLE_QUOTES + " label=" + CharPool.DOUBLE_QUOTES + ebi.getName() + CharPool.DOUBLE_QUOTES + " prop=" + CharPool.DOUBLE_QUOTES + c + CharPool.DOUBLE_QUOTES + " min-width=" + CharPool.DOUBLE_QUOTES + calcColumnWidth(ebi.getName()) + "px" + CharPool.DOUBLE_QUOTES + " sortable show-overflow-tooltip />");
                    break;
                case TIMESTAMP:
                    list.add("      <el-table-column align=" + CharPool.DOUBLE_QUOTES + "center" + CharPool.DOUBLE_QUOTES + " label=" + CharPool.DOUBLE_QUOTES + ebi.getName() + CharPool.DOUBLE_QUOTES + " prop=" + CharPool.DOUBLE_QUOTES + c + CharPool.DOUBLE_QUOTES + " min-width=" + CharPool.DOUBLE_QUOTES + calcColumnWidth(ebi.getName()) + "px" + CharPool.DOUBLE_QUOTES + " sortable show-overflow-tooltip>");
                    list.add("        <template v-slot=" + CharPool.DOUBLE_QUOTES + "{row}" + CharPool.DOUBLE_QUOTES + ">{{ row." + c + " }}</template>");
                    list.add("      </el-table-column>");
                    break;
            }
        }
        list.add("      <el-table-column align=" + CharPool.DOUBLE_QUOTES + "center" + CharPool.DOUBLE_QUOTES + " label=" + CharPool.DOUBLE_QUOTES + "创建时间" + CharPool.DOUBLE_QUOTES + " width=" + CharPool.DOUBLE_QUOTES + "160px" + CharPool.DOUBLE_QUOTES + " prop=" + CharPool.DOUBLE_QUOTES + "createTime" + CharPool.DOUBLE_QUOTES + " />");
        list.add("      <el-table-column align=" + CharPool.DOUBLE_QUOTES + "center" + CharPool.DOUBLE_QUOTES + " label=" + CharPool.DOUBLE_QUOTES + "最后修改时间" + CharPool.DOUBLE_QUOTES + " width=" + CharPool.DOUBLE_QUOTES + "160px" + CharPool.DOUBLE_QUOTES + " prop=" + CharPool.DOUBLE_QUOTES + "updateTime" + CharPool.DOUBLE_QUOTES + " />");
        list.add("      <el-table-column align=" + CharPool.DOUBLE_QUOTES + "center" + CharPool.DOUBLE_QUOTES + " label=" + CharPool.DOUBLE_QUOTES + "操作" + CharPool.DOUBLE_QUOTES + " width=" + CharPool.DOUBLE_QUOTES + "160px" + CharPool.DOUBLE_QUOTES + " fixed=" + CharPool.DOUBLE_QUOTES + "right" + CharPool.DOUBLE_QUOTES + ">");
        list.add("        <template v-slot=" + CharPool.DOUBLE_QUOTES + "{row}" + CharPool.DOUBLE_QUOTES + ">");
        list.add("          <el-button type=" + CharPool.DOUBLE_QUOTES + "primary" + CharPool.DOUBLE_QUOTES + " link @click=" + CharPool.DOUBLE_QUOTES + "handleView(row)" + CharPool.DOUBLE_QUOTES + ">查看</el-button>");
        list.add("          <el-button v-show=" + CharPool.DOUBLE_QUOTES + "checkAuthByCode('" + resourceCode + "')" + CharPool.DOUBLE_QUOTES + " type=" + CharPool.DOUBLE_QUOTES + "primary" + CharPool.DOUBLE_QUOTES + " link @click=" + CharPool.DOUBLE_QUOTES + "handleEdit(row)" + CharPool.DOUBLE_QUOTES + ">编辑</el-button>");
        list.add("          <el-popconfirm confirm-button-text=" + CharPool.DOUBLE_QUOTES + "确定" + CharPool.DOUBLE_QUOTES);
        list.add("                         cancel-button-text=" + CharPool.DOUBLE_QUOTES + "取消" + CharPool.DOUBLE_QUOTES);
        list.add("                         :icon=" + CharPool.DOUBLE_QUOTES + "WarningFilled" + CharPool.DOUBLE_QUOTES);
        list.add("                         icon-color=" + CharPool.DOUBLE_QUOTES + "#626AEF" + CharPool.DOUBLE_QUOTES);
        list.add("                         title=" + CharPool.DOUBLE_QUOTES + "您确定删除么？" + CharPool.DOUBLE_QUOTES);
        list.add("                         @confirm=" + CharPool.DOUBLE_QUOTES + "handleDelete(row)" + CharPool.DOUBLE_QUOTES);
        list.add("                         v-if=" + CharPool.DOUBLE_QUOTES + "checkAuthByCode('" + resourceCode + "')" + CharPool.DOUBLE_QUOTES + ">");
        list.add("            <template #reference>");
        list.add("              <el-button type=" + CharPool.DOUBLE_QUOTES + "danger" + CharPool.DOUBLE_QUOTES + " link>删除</el-button>");
        list.add("            </template>");
        list.add("          </el-popconfirm>");
        list.add("        </template>");
        list.add("      </el-table-column>");
        list.add("    </el-table>");
        list.add("    <pagination v-show=" + CharPool.DOUBLE_QUOTES + "total>0" + CharPool.DOUBLE_QUOTES + " v-model:total=" + CharPool.DOUBLE_QUOTES + "total" + CharPool.DOUBLE_QUOTES + " v-model:page=" + CharPool.DOUBLE_QUOTES + "listQuery." + Constants.PAGE_NUM + CharPool.DOUBLE_QUOTES + " v-model:limit=" + CharPool.DOUBLE_QUOTES + "listQuery." + Constants.PAGE_SIZE + CharPool.DOUBLE_QUOTES + " @pagination=" + CharPool.DOUBLE_QUOTES + "getList" + CharPool.DOUBLE_QUOTES + " />");
        list.add("    <el-dialog v-model=" + CharPool.DOUBLE_QUOTES + "dialogVisible" + CharPool.DOUBLE_QUOTES + " :title=" + CharPool.DOUBLE_QUOTES + "dialogTypeTitle" + CharPool.DOUBLE_QUOTES + " width=" + CharPool.DOUBLE_QUOTES + "70%" + CharPool.DOUBLE_QUOTES + " top=" + CharPool.DOUBLE_QUOTES + "2vh" + CharPool.DOUBLE_QUOTES + ">");
        list.add("      <el-form class=" + CharPool.DOUBLE_QUOTES + "my-form" + CharPool.DOUBLE_QUOTES + " ref=" + CharPool.DOUBLE_QUOTES + "obj" + CharPool.DOUBLE_QUOTES + " :model=" + CharPool.DOUBLE_QUOTES + "obj" + CharPool.DOUBLE_QUOTES + " :rules=" + CharPool.DOUBLE_QUOTES + "rules" + CharPool.DOUBLE_QUOTES + " label-position=" + CharPool.DOUBLE_QUOTES + "right" + CharPool.DOUBLE_QUOTES + " :disabled=" + CharPool.DOUBLE_QUOTES + "dialogType === 'view'" + CharPool.DOUBLE_QUOTES + " label-width=" + CharPool.DOUBLE_QUOTES + "auto" + CharPool.DOUBLE_QUOTES + " label-suffix=" + CharPool.DOUBLE_QUOTES + "：" + CharPool.DOUBLE_QUOTES + ">");
        list.add("        <el-form-item v-show=" + CharPool.DOUBLE_QUOTES + "isDebug" + CharPool.DOUBLE_QUOTES + " label=" + CharPool.DOUBLE_QUOTES + "ID" + CharPool.DOUBLE_QUOTES + ">");
        list.add("          <text>{{ obj.id }}</text>");
        list.add("        </el-form-item>");
        for (ExcelBeanItem ebi : eb.getList()) {
            String c = StrUtil.toCamelCase(ebi.getColumn().toLowerCase());
            switch (ebi.getJdbcType()) {
                case CLOB:
                    list.add("        <el-form-item label=" + CharPool.DOUBLE_QUOTES + ebi.getName() + CharPool.DOUBLE_QUOTES + " prop=" + CharPool.DOUBLE_QUOTES + c + CharPool.DOUBLE_QUOTES + ">");
                    list.add("          <el-input v-model=" + CharPool.DOUBLE_QUOTES + "obj." + c + CharPool.DOUBLE_QUOTES + " :autosize=" + CharPool.DOUBLE_QUOTES + "{ minRows: 2, maxRows: 5}" + CharPool.DOUBLE_QUOTES + " type=" + CharPool.DOUBLE_QUOTES + "textarea" + CharPool.DOUBLE_QUOTES + " />");
                    list.add("        </el-form-item>");
                    break;
                case VARCHAR:
                    if (ebi.getLength() >= 1000) {
                        list.add("        <el-form-item label=" + CharPool.DOUBLE_QUOTES + ebi.getName() + CharPool.DOUBLE_QUOTES + " prop=" + CharPool.DOUBLE_QUOTES + c + CharPool.DOUBLE_QUOTES + ">");
                        list.add("          <el-input v-model=" + CharPool.DOUBLE_QUOTES + "obj." + c + CharPool.DOUBLE_QUOTES + " :autosize=" + CharPool.DOUBLE_QUOTES + "{ minRows: 2, maxRows: 5}" + CharPool.DOUBLE_QUOTES + " type=" + CharPool.DOUBLE_QUOTES + "textarea" + CharPool.DOUBLE_QUOTES + " />");
                        list.add("        </el-form-item>");
                    } else {
                        if (StrUtil.isNotBlank(ebi.getValueEnum())) {
                            list.add("        <el-form-item label=" + CharPool.DOUBLE_QUOTES + ebi.getName() + CharPool.DOUBLE_QUOTES + " prop=" + CharPool.DOUBLE_QUOTES + c + CharPool.DOUBLE_QUOTES + ">");
                            list.add("          <el-radio-group v-model=" + CharPool.DOUBLE_QUOTES + "obj." + c + CharPool.DOUBLE_QUOTES + ">");
                            list.add("            <el-radio-button v-for=" + CharPool.DOUBLE_QUOTES + "(item,index) in getEnumList('" + ebi.getValueEnum() + "')" + CharPool.DOUBLE_QUOTES + " :label=" + CharPool.DOUBLE_QUOTES + "item.key" + CharPool.DOUBLE_QUOTES + " :key=" + CharPool.DOUBLE_QUOTES + "index" + CharPool.DOUBLE_QUOTES + ">{{item.value}}</el-radio-button>");
                            list.add("          </el-radio-group>");
                            list.add("        </el-form-item>");
                            break;
                        } else if (StrUtil.isNotBlank(ebi.getValueDict())) {
                            list.add("        <el-form-item label=" + CharPool.DOUBLE_QUOTES + ebi.getName() + "(数据字典)" + CharPool.DOUBLE_QUOTES + " prop=" + CharPool.DOUBLE_QUOTES + c + CharPool.DOUBLE_QUOTES + ">");
                            list.add("          <el-select v-model=" + CharPool.DOUBLE_QUOTES + "obj." + c + CharPool.DOUBLE_QUOTES + " class=" + CharPool.DOUBLE_QUOTES + "m-2" + CharPool.DOUBLE_QUOTES + " placeholder=" + CharPool.DOUBLE_QUOTES + "请选择" + CharPool.DOUBLE_QUOTES + ">");
                            list.add("            <el-option key=" + CharPool.DOUBLE_QUOTES + CharPool.DOUBLE_QUOTES + " label=" + CharPool.DOUBLE_QUOTES + "请选择" + CharPool.DOUBLE_QUOTES + " value=" + CharPool.DOUBLE_QUOTES + CharPool.DOUBLE_QUOTES + " />");
                            list.add("            <el-option v-for=" + CharPool.DOUBLE_QUOTES + "item in getDictList('" + ebi.getValueDict() + "')" + CharPool.DOUBLE_QUOTES + " :key=" + CharPool.DOUBLE_QUOTES + "item.key" + CharPool.DOUBLE_QUOTES + " :label=" + CharPool.DOUBLE_QUOTES + "`${item.key} - ${item.value}`" + CharPool.DOUBLE_QUOTES + " :value=" + CharPool.DOUBLE_QUOTES + "item.key" + CharPool.DOUBLE_QUOTES + " />");
                            list.add("          </el-select>");
                            list.add("        </el-form-item>");
                            break;
                        } else if (StrUtil.isNotBlank(ebi.getValueForeign())) {
                            //TODO
                        } else {
                            list.add("        <el-form-item label=" + CharPool.DOUBLE_QUOTES + ebi.getName() + CharPool.DOUBLE_QUOTES + " prop=" + CharPool.DOUBLE_QUOTES + c + CharPool.DOUBLE_QUOTES + ">");
                            list.add("          <el-input v-model=" + CharPool.DOUBLE_QUOTES + "obj." + c + CharPool.DOUBLE_QUOTES + " placeholder=" + CharPool.DOUBLE_QUOTES + "请输入" + ebi.getName() + "，最多输入" + ebi.getLength() + "个字符" + CharPool.DOUBLE_QUOTES + " />");
                            list.add("        </el-form-item>");
                        }
                        // list.add("        <el-form-item label=" + CharPool.DOUBLE_QUOTES + ebi.getName() + CharPool.DOUBLE_QUOTES + " prop=" + CharPool.DOUBLE_QUOTES + c + CharPool.DOUBLE_QUOTES + ">");
                        // list.add("          <el-input v-model=" + CharPool.DOUBLE_QUOTES + "obj." + c + CharPool.DOUBLE_QUOTES + " placeholder=" + CharPool.DOUBLE_QUOTES + "请输入" + ebi.getName() + CharPool.DOUBLE_QUOTES + " />");
                        // list.add("        </el-form-item>");
                    }
                    break;
                case DECIMAL:
                case INTEGER:
                    list.add("        <el-form-item label=" + CharPool.DOUBLE_QUOTES + ebi.getName() + CharPool.DOUBLE_QUOTES + " prop=" + CharPool.DOUBLE_QUOTES + c + CharPool.DOUBLE_QUOTES + ">");
                    list.add("          <el-input-number v-model=" + CharPool.DOUBLE_QUOTES + "obj." + c + CharPool.DOUBLE_QUOTES + " placeholder=" + CharPool.DOUBLE_QUOTES + "请输入" + ebi.getName() + CharPool.DOUBLE_QUOTES + " />");
                    list.add("        </el-form-item>");
                    break;
                case BIGINT:
                    list.add("        <el-form-item label=" + CharPool.DOUBLE_QUOTES + ebi.getName() + CharPool.DOUBLE_QUOTES + " prop=" + CharPool.DOUBLE_QUOTES + c + CharPool.DOUBLE_QUOTES + ">");
                    list.add("          <el-input v-model=" + CharPool.DOUBLE_QUOTES + "obj." + c + CharPool.DOUBLE_QUOTES + " type=" + CharPool.DOUBLE_QUOTES + "number" + CharPool.DOUBLE_QUOTES + " placeholder=" + CharPool.DOUBLE_QUOTES + "请输入" + ebi.getName() + CharPool.DOUBLE_QUOTES + " />");
                    list.add("        </el-form-item>");
                    break;
                case TIMESTAMP:
                    list.add("        <el-form-item label=" + CharPool.DOUBLE_QUOTES + ebi.getName() + CharPool.DOUBLE_QUOTES + " prop=" + CharPool.DOUBLE_QUOTES + c + CharPool.DOUBLE_QUOTES + ">");
                    list.add("          <el-date-picker v-model=" + CharPool.DOUBLE_QUOTES + "obj." + c + CharPool.DOUBLE_QUOTES + " placeholder=" + CharPool.DOUBLE_QUOTES + "请输入" + ebi.getName() + CharPool.DOUBLE_QUOTES + " type=" + CharPool.DOUBLE_QUOTES + "datetime" + CharPool.DOUBLE_QUOTES + " value-format=" + CharPool.DOUBLE_QUOTES + "YYYY-MM-DD HH:mm:ss" + CharPool.DOUBLE_QUOTES + " />");
                    list.add("        </el-form-item>");
                    break;
            }
        }
        list.add("        <el-form-item label=" + CharPool.DOUBLE_QUOTES + "创建时间" + CharPool.DOUBLE_QUOTES + ">");
        list.add("          <text>{{ obj.createTime || '自动生成' }}</text>");
        list.add("        </el-form-item>");
        list.add("        <el-form-item label=" + CharPool.DOUBLE_QUOTES + "最后修改时间" + CharPool.DOUBLE_QUOTES + ">");
        list.add("          <text>{{ obj.updateTime || '自动生成' }}</text>");
        list.add("        </el-form-item>");
        list.add("        <el-form-item v-show=" + CharPool.DOUBLE_QUOTES + "isDebug" + CharPool.DOUBLE_QUOTES + " label=" + CharPool.DOUBLE_QUOTES + "数据版本" + CharPool.DOUBLE_QUOTES + ">");
        list.add("          <text>{{ obj.version }}</text>");
        list.add("        </el-form-item>");
        list.add("      </el-form>");
        list.add("      <div style=" + CharPool.DOUBLE_QUOTES + "text-align:right;" + CharPool.DOUBLE_QUOTES + ">");
        list.add("        <el-button type=" + CharPool.DOUBLE_QUOTES + "info" + CharPool.DOUBLE_QUOTES + " icon=" + CharPool.DOUBLE_QUOTES + "Close" + CharPool.DOUBLE_QUOTES + " @click=" + CharPool.DOUBLE_QUOTES + "dialogVisible=false" + CharPool.DOUBLE_QUOTES + ">关闭</el-button>");
        list.add("        <el-button type=" + CharPool.DOUBLE_QUOTES + "primary" + CharPool.DOUBLE_QUOTES + " icon=" + CharPool.DOUBLE_QUOTES + "Check" + CharPool.DOUBLE_QUOTES + " v-show=" + CharPool.DOUBLE_QUOTES + "dialogType !== 'view'" + CharPool.DOUBLE_QUOTES + " @click=" + CharPool.DOUBLE_QUOTES + "doConfirm('obj')" + CharPool.DOUBLE_QUOTES + ">确定</el-button>");
        list.add("      </div>");
        list.add("    </el-dialog>");
        list.add("  </div>");
        list.add("</template>");
        list.add("");
        list.add("<script>");
        list.add("import baseConfig from '@/mixins/baseConfig'");
        list.add("import {doGet, doPost, doPut, doDelete, doGetDownload} from '@/config/http'");
        list.add("import {alertErrorMsg, customValidator, notifySuccess} from '@/config/common'");
        list.add("import InputTagDialog from '@/components/InputTag/inputTagDialog.vue';");
        list.add("import SvgIcon from '@/components/SvgIcon/index.vue';");
        list.add("");
        list.add("const emptyObj = {");
        for (int i = 0; i < eb.getList().size(); i++) {
            ExcelBeanItem ebi = eb.getList().get(i);
            String c = StrUtil.toCamelCase(ebi.getColumn().toLowerCase());
            if (StrUtil.isBlank(ebi.getDefaultVal())) {
                list.add("  " + c + ": null, // " + ebi.getName());
            } else {
                switch (ebi.getJdbcType()) {
                    case CLOB:
                    case VARCHAR:
                        list.add("  " + c + ": '" + ebi.getDefaultVal() + "', // " + ebi.getName());
                        break;
                    case DECIMAL:
                    case BIGINT:
                    case INTEGER:
                        list.add("  " + c + ": " + ebi.getDefaultVal() + ", // " + ebi.getName());
                        break;
                    case TIMESTAMP:
                        list.add("  " + c + ": null, // " + ebi.getName());
                        break;
                }
            }
        }
        list.add("  id: null,");
        list.add("  createBy: null,");
        list.add("  createTime: null,");
        list.add("  updateBy: null,");
        list.add("  updateTime: null,");
        list.add("  deleted: null,");
        list.add("  version: null,");
        list.add("}");
        list.add("");
        list.add("export default {");
        list.add("  name: '" + title + "_nocache',");
        list.add("  components: {SvgIcon, InputTagDialog},");
        list.add("  mixins: [baseConfig],");
        list.add("  data() {");
        list.add("    const svc = '" + applicationName() + "'");
        list.add("    return {");
        list.add("      svc,");
        list.add("      obj: Object.assign({}, emptyObj),");
        list.add("      routes: [],");
        list.add("      nameOfPermission: null,");
        list.add("      dialogVisible: false,");
        list.add("      dialogType: 'add',");
        list.add("      dialogTypeTitle: '新增',");
        list.add("      checkStrictly: false,");
        list.add("      defaultProps: {");
        list.add("        children: 'children',");
        list.add("        label: 'title'");
        list.add("      },");
        list.add("      tableKey: 0,");
        list.add("      list: null,");
        list.add("      total: 0,");
        list.add("      listLoading: false,");
        list.add("      listQuery: {");
        list.add("        " + Constants.PAGE_NUM + ": " + Constants.DEFAULT_PAGE_NUM + ",");
        list.add("        " + Constants.PAGE_SIZE + ": " + Constants.DEFAULT_PAGE_SIZE + ",");
        list.add("        " + Constants.SORT_FIELD + ": '" + Constants.DEFAULT_SORT_FIELD + "',");
        list.add("        " + Constants.SORT_TYPE + ": '" + Constants.SORT_DESC + "',");
        for (ExcelBeanItem ebi : eb.getList()) {
            String c = StrUtil.toCamelCase(ebi.getColumn().toLowerCase());
            switch (ebi.getJdbcType()) {
                case CLOB:
                    break;
                case VARCHAR:
                case DECIMAL:
                case BIGINT:
                case INTEGER:
                    list.add("        " + c + ": null,");
                    break;
                case TIMESTAMP:
                    list.add("        " + c + "Start: null,");
                    list.add("        " + c + "End: null,");
                    list.add("        " + c + "Range: [],//");
                    break;
            }
        }
        list.add("        createTimeStart: null,");
        list.add("        createTimeEnd: null,");
        list.add("        updateTimeStart: null,");
        list.add("        updateTimeEnd: null,");
        list.add("      },");
        list.add("      selectionList: [],");
        list.add("      dialogFormVisible: false,");
        list.add("      dialogStatus: '',");
        list.add("      rules: {");
        for (int i = 0; i < eb.getList().size(); i++) {
            ExcelBeanItem ebi = eb.getList().get(i);
            String c = StrUtil.toCamelCase(ebi.getColumn().toLowerCase());
            boolean required = false;
            int min = 0;
            int max = 0;
            if ("否".equals(ebi.getIsnull())) {
                min = 1;
                required = true;
            }
            switch (ebi.getJdbcType()) {
                case CLOB:
                    break;
                case VARCHAR:
                case DECIMAL:
                case BIGINT:
                case INTEGER:
                    max = ebi.getLength();
                    break;
                case TIMESTAMP:
                    max = 20;
                    break;
            }
            list.add("        " + c + ": [{ required: " + required + ", validator: customValidator, min: " + min + ", max: " + max + ", label: '" + ebi.getName() + "', trigger: ['blur', 'change'] }],");
        }
        list.add("      },");
        list.add("    }");
        list.add("  },");
        list.add("  computed: {");
        list.add("    routesData() {");
        list.add("      return this.routes");
        list.add("    },");
        list.add("  },");
        list.add("  created() {");
        list.add("    this.nameOfPermission = '" + title + "'");
        list.add("    this.getFavorite(this.nameOfPermission)?.then(res => this.userFavorites = res)");
        list.add("    this.initList()");
        list.add("    this.getList()");
        list.add("  },");
        list.add("  methods: {");
        list.add("    async initList() {");
        list.add("    },");
        list.add("    getList() {");
        list.add("      this.listLoading = true");
        for (ExcelBeanItem ebi : eb.getList()) {
            String c = StrUtil.toCamelCase(ebi.getColumn().toLowerCase());
            switch (ebi.getJdbcType()) {
                case CLOB:
                case VARCHAR:
                case DECIMAL:
                case BIGINT:
                case INTEGER:
                    break;
                case TIMESTAMP:
                    list.add("      this.listQuery." + c + "Start = ''");
                    list.add("      this.listQuery." + c + "End = ''");
                    list.add("      if (this.listQuery." + c + "Range) {");
                    list.add("        this.listQuery." + c + "Start = this.listQuery." + c + "Range[0]");
                    list.add("        this.listQuery." + c + "End = this.listQuery." + c + "Range[1]");
                    list.add("      }");
                    break;
            }
        }
        list.add("      doGet(this.svc, '/" + StrUtil.toSymbolCase(title, '-') + "/page', this.listQuery).then(res => {");
        list.add("        this.listLoading = false");
        list.add("        this.list = res['records']");
        list.add("        this.total = parseInt(res['total'])");
        list.add("      }).catch(e => {");
        list.add("        console.error(e)");
        list.add("        this.listLoading = false");
        list.add("      })");
        list.add("    },");
        list.add("    handleResetQuery() {");
        list.add("      this.resetForm(" + CharPool.DOUBLE_QUOTES + "listQuery" + CharPool.DOUBLE_QUOTES + ")");
        for (ExcelBeanItem ebi : eb.getList()) {
            String c = StrUtil.toCamelCase(ebi.getColumn().toLowerCase());
            switch (ebi.getJdbcType()) {
                case CLOB:
                case VARCHAR:
                case DECIMAL:
                case BIGINT:
                case INTEGER:
                    break;
                case TIMESTAMP:
                    list.add("      this.listQuery." + c + "Start = ''");
                    list.add("      this.listQuery." + c + "End = ''");
                    list.add("      this.listQuery." + c + "Range = []");
                    break;
            }
        }
        list.add("    },");
        list.add("    handleFilter() {");
        list.add("      this.listQuery." + Constants.PAGE_NUM + " = 1");
        list.add("      this.getList()");
        list.add("    },");
        list.add("    handleModifyStatus(row, status) {");
        list.add("      this.$message({");
        list.add("        message: '操作Success',");
        list.add("        type: 'success'");
        list.add("      })");
        list.add("      row.status = status");
        list.add("    },");
        list.add("    handleSelectionChange(data) {");
        list.add("      this.selectionList = data");
        list.add("    },");
        list.add("    handleSortChange(data) {");
        list.add("      const { prop, order } = data");
        list.add("      this.listQuery." + Constants.SORT_FIELD + " = prop");
        list.add("      this.listQuery." + Constants.SORT_TYPE + " = order === 'ascending' ? '" + Constants.SORT_ASC + "' : '" + Constants.SORT_DESC + "'");
        list.add("      this.handleFilter()");
        list.add("    },");
        list.add("    handleEdit(row) {");
        list.add("      this.dialogType = 'edit'");
        list.add("      this.dialogTypeTitle = '编辑'");
        list.add("      this.dialogVisible = true");
        list.add("      this.checkStrictly = true");
        list.add("      this.obj = Object.assign({}, row)");
        list.add("    },");
        list.add("    handleView(row) {");
        list.add("      this.dialogType = 'view'");
        list.add("      this.dialogTypeTitle = '详情'");
        list.add("      this.dialogVisible = true");
        list.add("      this.checkStrictly = false");
        list.add("      this.obj = Object.assign({}, row)");
        list.add("    },");
        list.add("    handleAdd() {");
        list.add("      this.dialogType = 'add'");
        list.add("      this.dialogTypeTitle = '新增'");
        list.add("      this.dialogVisible = true");
        list.add("      this.checkStrictly = true");
        list.add("      this.obj = Object.assign({}, emptyObj)");
        list.add("    },");
        list.add("    handleExport() {");
        list.add("      doGetDownload(this.svc, '/" + StrUtil.toSymbolCase(title, '-') + "/export', this.listQuery)");
        list.add("    },");
        list.add("    handleDelete(row) {");
        list.add("      doDelete(this.svc, `/" + StrUtil.toSymbolCase(title, '-') + "/${row.id}`, {}).then(res => {");
        list.add("        if (res > 0) {");
        list.add("          notifySuccess('操作成功')");
        list.add("          this.getList()");
        list.add("        }");
        list.add("        this.dialogVisible = false");
        list.add("      })");
        list.add("    },");
        list.add("    async doConfirm(formName) {");
        list.add("      this.$refs[formName].validate(valid => {");
        list.add("        if (!valid) {");
        list.add("          alertErrorMsg('表单验证不通过，请检查数据。')");
        list.add("          return");
        list.add("        }");
        list.add("        switch (this.dialogType) {");
        list.add("          case 'add': {");
        list.add("            doPost(this.svc, '/" + StrUtil.toSymbolCase(title, '-') + "/add', this.obj).then(() => {");
        list.add("              notifySuccess('新增成功')");
        list.add("              this.getList()");
        list.add("              this.dialogVisible = false");
        list.add("            })");
        list.add("            break");
        list.add("          }");
        list.add("          case 'edit': {");
        list.add("            doPut(this.svc, '/" + StrUtil.toSymbolCase(title, '-') + "/modify', this.obj).then(() => {");
        list.add("              notifySuccess('修改成功')");
        list.add("              this.getList()");
        list.add("              this.dialogVisible = false");
        list.add("            })");
        list.add("            break");
        list.add("          }");
        list.add("        }");
        list.add("      })");
        list.add("    }");
        list.add("  }");
        list.add("}");
        list.add("</script>");
        writeFile(file, list);
    }

    private int calcColumnWidth(String label) {
        if (label.length() == 2) {
            return 80;
        }
        int width = label.length() * 25 + 5;
        return Math.max(width, 120);
    }

    private String applicationName() {
        JSONObject dict = YamlUtil.loadByPath("classpath:bootstrap.yml", JSONObject.class);
        JSONObject spring = dict.getJSONObject("spring");
        JSONObject application = spring.getJSONObject("application");
        return application.getStr("name");
    }

    @Data
    private static class ExcelBean {
        private String title;
        private String desc;
        private String module;
        private String service;
        private List<ExcelBeanItem> list;

        private String getServiceModule(String split) {
            if (StrUtil.isBlank(service)) {
                return module;
            }
            return service + split + module;
        }
    }

    @Data
    private static class ExcelBeanItem {
        private String name;//名称
        private String column;//数据库列
        private String type;//类型
        private Integer length;//长度
        private Integer precision;//精度
        private String isnull;//是否可空
        private String defaultVal;//默认值
        private String remark;//备注
        private String isAccurate;//是否精确查询
        private String autoValuePrefix;//自动生成前缀
        private String valueEnum;//枚举类
        private String valueDict;//数据字典key
        private String valueForeign;//外键表
        private JDBCType jdbcType;
    }

    private enum ConfigType {
        printExists,
        printExcel,
        printCreateTable,
    }

}
